Java 工程的外部依赖显示工具实现及使用
缪 旭晖 和 沙 龙泉
2014 年 12 月 24 日发布
背景
在测试中发现,我们的一个类错误地引用了外部接口,这个接口有不同的实现方案,应该如何确保调用了正确的接口?整个项目中是否还有其他类似错误的引用?为此我们开发了这个工具,能够清晰地列出接口引用关系,希望对其他碰到类似情况的开发人员有所帮助。
实现原理
分析源文件引用接口及 Jar 文件导出接口
分析源文件的引用接口可以直接通过逐行扫描源代码,读取导入的包,然后找出所有的符号,再进一步分析符号调用的 Jar 文件接口,或者可以通过 Java 编译器编译源代码,再从编译后的符号表中读取符号信息。第一种方法要自己分析源代,实现复杂写,但是运行效率要比 Java 编译器编译源代码高很多,因为 Java 编译器编译过程对源码所有的符号做了详细的分析,而我们只了解源码中引用了哪些外部接口。第二种方法虽然实现比较简单,可以使用开源的通用 Java
编译器 GJC(Generic Java
Compiler),但是 GJC 本身还是比较复杂,需要了解 GJC 的接口,本章会在后面做介绍。当然并不局限这两种方法,例如,可以只使用 GJC 或者其他 Java 编译器提供的接口做源代码解析,不进行完整的编译,然后对解析后的符号表进行过滤只留下感兴趣的引用外部引用接口的符号,最后再分析接口关系。
利用扫描源代码的方法进行接口分析
清单 1. 读取 Jar 文件获取类名代码Java.util.jar.JarFile jarFile = new Java.util.jar.JarFile(file);
Enumeration entries = jarFile.entries();
//读取 jar 文件把类名保存到 map 中
public boolean append(File file) throws IOException{ //jar file
String path = file.getAbsolutePath();
JarFile jarFile=new JarFile(file);
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements()){
JarEntry ent = entries.nextElement();
String name = ent.getName();
if(name.endsWith(".class")){
name = name.substring(0,name.length()-6).replace('/', '.');
map.put(name, path);
}
}
ret