不幸的是,您的问题充满了缺点:
- 当然,您可以解析输入源(通过 Javacc 或 ANTLR 解析器),直到到达所需的行。
.class
但是,由于您已经拥有文件,因此解析相同的源似乎是浪费精力。
.class
因此,分析文件似乎更好。但不幸的是,你不能保证这是你的行产生的类,因为在同一个源文件中可以定义多个类。
啊!这让我想到了一种复杂的解决方案:
我将声明一个包含所有登录名的类:
public class SourceMethodsIndexer
{
private final SortedMap<Integer, List<Method>> indexOfMethodsByFirstLineNumber;
}
构造函数将是这样的:
public SourceMethodsIndexer(File sourceFile)
...并且应该执行以下任务:
1.浏览目标包相关的类目录。
File targetPackageDir=getTargetPackageDir(sourceFile);
File[] classFiles=targetPackageDir.listFiles(new FileFilter(){
public boolean accept(File dir, String name){
return name.endsWith(".class");
}
});
2.使用Apache BCEL收集属于你的输入源文件的所有非公共类(你可以调用JavaClass.getSourceFileName()
过滤类),加上你的输入源文件名对应的公共类。
Collection<JavaClass> targetClasses=getNonPublicClasses(classFiles, sourceFile.getName());
targetClasses.add(publicClass);
3.然后收集每个类中的所有方法。
Set<Method> targetMethods=new HashSet<Method>(1024);
for (JavaClass javaClass:targetClasses)
{
targetMethods.addAll(Arrays.asList(javaClass.getMethods()));
}
4.现在您可以直接搜索您的行号,也可以先按行号索引方法以便稍后更快地访问它们:(JavaClass.getMethods()[n].getLineNumberTable().getSourceLine(0)
注意可能存在重复值)。
this.indexOfMethodsByFirstLineNumber=new TreeMap<Integer, List<Method>>((int)(1.7d*methods.size()));
for (Method method: methods)
{
// Note: The -1 in this line stands to make the SortedMap work properly when searching for ranges.
int firstLine=getLineNumberTable().getSourceLine(0)-1;
List<Method> methodsInTheSameLine=indexOfMethodsByFirstLineNumber.get(firstLine);
if (methodsInTheSameLine==null)
{
methodsInTheSameLine=new ArrayList<Method>();
indexOfMethodsByFirstLineNumber.put(firstLine,methodsInTheSameLine);
}
methodsInTheSameLine.add(method);
}
5.Public一个方法来做搜索:
public Method getMethodByLine(int lineNumber)
{
Set<Method> methodsInTheSameLine=this.indexOfMethodsByFirstLineNumber.headMap(lineNumber).lastKey();
if (methodsInTheSameLine.size()==0)
{
// There are no methods method in that line: Absurd.
}
else if (methodsInTheSameLine.size()>1)
{
// There are more than one method in that line. Hardly probable, but possible.
}
else
{
// There is one method in that line:
return methods.get(0);
}
}