假设我有一个与以下相同的Java源文件(source.java
)。
1 package demo;
2
3 public class Source {
4
5 public static void main(String[] args) {
6
7 String sample = "foo bar";
8
9 System.out.println(sample.length());
10
11 }
12 }
现在,我想编写一个Java代码,逐行读取此源文件,当它在第9行遇到sample
变量时,它将为我提供示例的哪个类(即java.lang.String
)变量属于。我怎样才能做到这一点?
我已经看过下面的链接,该链接对我不起作用,因为它在同一源文件中打印类型名称。
答案 0 :(得分:4)
要读取独立的Java源文件,必须从头开始,逐行读取,按照Java的语法解析文件的每个单词,...要做的工作太多。或者我推荐JavaParser。
JavaParser读取原始Java源文件并将其解析为一个Java对象,您可以检索该信息。
这是您的问题的示例代码:
public String getSampleVariableType() throws Exception {
// Use the raw text of file as input
// `CompilationUnit` contains all information of your Java file.
CompilationUnit compilationUnit = JavaParser.parse("package demo;\n" +
"\n" +
"public class Source {\n" +
" public static void main(String[] args) {\n" +
" String sample = \"foo bar\"; \n" +
" System.out.println(sample.length());\n" +
" }\n" +
"}");
// Find class by name
ClassOrInterfaceDeclaration clazz = compilationUnit.getClassByName("Source")
.orElse(null);
if (clazz == null)
throw new ClassNotFoundException();
// Find method by name
List<MethodDeclaration> methods = clazz.getMethodsByName("main");
if (methods.size() == 0)
throw new MethodNotFoundException();
// Get the content of method's body
MethodDeclaration method = methods.get(0);
BlockStmt block = method.getBody().orElse(null);
if (block == null)
throw new MethodEmptyException();
// Statement `String sample = "foo bar";` is a VariableDeclaration.
// Find all VariableDeclaration in current method, filter as you want
// and get its class type by using `getType()` method
return block.findAll(VariableDeclarator.class).stream()
.filter(v -> v.getName().asString().equals("sample"))
.map(v -> v.getType().asString())
.findFirst().orElse(null);
}
结果是类型为String
的简单名称。
为了将结果表示为完全限定的名称(即java.lang.String
)。您可能需要查找所有ImportDeclaration
并找到导入的名称:
public static String getFullyQualifiedName(CompilationUnit cu, String simpleName) {
return cu.findAll(ImportDeclaration.class).stream()
.filter(i -> i.getName().asString().matches(".*\\b" + simpleName + "\\b"))
.map(i -> i.getName().asString())
.findFirst().orElse("java.lang." + simpleName);
}
答案 1 :(得分:0)
这里是尝试使用正则表达式进行解析的不完整工具(某些TODO项),我们可以先使用#luckFindInScope()进行尝试,如果失败,则尝试使用复杂的源代码进行复杂的处理。
package com.mytest.core.share;
import java.io.File;
import java.io.FileInputStream;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
public class TestParse {
public static void main(String[] args) throws Exception {
//testHit();
testNotHit();
}
public static void testNotHit() throws Exception {
// input position
int position = 511;
String id = "sample";
parse(position, id);
}
public static void testHit() throws Exception {
// input position
int position = 955;
String id = "sample";
parse(position, id);
}
public static void parse(int position, String id) throws Exception {
int end = position;
FileInputStream fs = new FileInputStream(new File("TestFile.java"));
String source = IOUtils.toString(fs, "UTF-8");
source = source.substring(0, end);
System.out.println("### look from" +source);
// remove all String in source code;
source = removeStringInSource(source);
int start = 0;
int stack = 0;// for nested scope
boolean hit = false;
// find the char '{' from the end of source
for (int i = source.length(); i > 0; i--) {
String current = source.substring(i - 1, i);
if (stack == 0) {
if (current.equals("{")) {
start = i;// lookup from start to end;
System.err.println("from this {, start to search from the location at " + i);
hit = findInScope(source, id, start, end);
end = start; // skip, search next scope;
if (hit) {
break;
} else {
continue;
}
}
}
// skip bracket pair {}
if (current.equals("}")) {
stack++;
end = i;// skip it;
}
if (current.equals("{")) {
stack--;
end = i;// skip it;
}
}
if (hit == false) {
// TODO: find the type in the class members and super class members
}
// TODO: find full class name in the java.lang.* or in the header of the source
// of import section.
}
private static boolean findInScope(String source, String id, int start, int end) {
String regex = "[A-Za-z0-9_$]+\\s+" + id;
String text = source.substring(start, end);
Matcher matcher = Pattern.compile(regex).matcher(text);
boolean result = matcher.find();
if (result) {
hitString = matcher.group();
System.err.println("hitString = " + hitString + " ,in the text scope: " + text);
}
return result;
}
private static boolean luckFindInScope(String source, String id) {
String regex = "[A-Za-z0-9_$]+\\s+" + id;
Matcher matcher = Pattern.compile(regex).matcher(source);
int count = 0;
while (matcher.find()) {
count++;
hitString= matcher.group();
}
return count == 1;
}
private static String hitString = "";
// fill star * in the string value
private static String removeStringInSource(String input) {
Matcher matcher = Pattern.compile("\".*?\"").matcher(input);
String match = "";
while(matcher.find()) {
match = matcher.group();
char[] symbols = new char[match.length()];
Arrays.fill(symbols, '*');
input = input.replace(match, new String(symbols));
}
System.out.println("$$ removed: " + input);
return input;
}
}
下面是更复杂的源代码:
package com.mytest.test.parse;
public class TestFile {
public static void main(String[] args) {
String sample = "foo bar";
System.out.println(sample.length());
}
public static String sample = null;
public static void test1() {
if (sample != null) {
{
String sample = "foo bar";
System.out.println(sample);
{
sample = "foo bar";
System.out.println(sample);
}
}
{
System.out.println(sample);
int test = 0;
{
if (test >= 0) {
sample = "foo bar";
System.out.println(sample);
String sample = "foo bar";
System.out.println(sample);
}
}
}
if(sample.equals("foo bar")) {
System.out.println(sample);
}
}
if( sample == null) {
String sample = "foo bar";
if(sample.equals("foo bar")) {
System.out.println(sample);
}
}
}
public static void test2{
if( sample == null) {
String sample = "foo bar";
if(sample.equals("foo bar")) {
System.out.println(sample);
}
}
}
}