我正在使用Java Compiler API编译内存类。也就是说,类被编译为字节码(没有存储在磁盘中的.classes文件),然后通过重构字节码加载。
有时,我需要编译一个依赖于另一个内存编译类的类。例如:编译A类,然后编译依赖于A类的B类。
为了解决这个问题,我将A类和B类作为编译器API的getTask方法所需的编译单元传递。
但是,我真的不喜欢这个解决方案,因为它让我重新编译已编译的A类。
有没有办法解决这个问题?
编辑:我通过此链接找到了解决方案:http://www.ibm.com/developerworks/java/library/j-jcomp/index.html
答案 0 :(得分:2)
是的,只要您正确实施ForwardingJavaFileManager
,这是完全可能的。最重要的两个方法是inferBinaryName()和list()。如果正确设置这两个,编译器将能够解析您之前编译的类。
inferBinaryName()
必须返回“simple name”类(例如com.test.Test
的推断二进制名称只是Test
)。这是我的实现(我的JavaFileObject
的子类称为InAppJavaFileObject
):
@Override
public String inferBinaryName(Location location, JavaFileObject javaFileObject) {
if(location == StandardLocation.CLASS_PATH && javaFileObject instanceof InAppJavaFileObject) {
return StringUtils.substringBeforeLast(javaFileObject.getName(), ".java");
}
return super.inferBinaryName(location, javaFileObject);
}
请注意,我从最后剥离了“.java”。构造JavaFileObject
时,文件名必须以“.java”结尾,但如果以后不删除后缀,编译器将找不到您的类。
list()
稍微复杂一点,因为你必须小心与你的委托文件管理器一起玩。在我的实现中,我将完全限定类名的映射保存到我可以迭代的JavaFileObject
子类中:
@Override
public Iterable<JavaFileObject> list(Location action, String pkg, Set<JavaFileObject.Kind> kind, boolean recurse) throws IOException {
Iterable<JavaFileObject> superFiles = super.list(action, pkg, kind, recurse);
// see if there's anything in our cache that matches the criteria.
if(action == StandardLocation.CLASS_PATH && (kind.contains(JavaFileObject.Kind.CLASS) || kind.contains(JavaFileObject.Kind.SOURCE))) {
List<JavaFileObject> ourFiles = new ArrayList<JavaFileObject>();
for(Map.Entry<String,InAppJavaFileObject> entry : files.entrySet()) {
String className = entry.getKey();
if(className.startsWith(pkg) && ("".equals(pkg) || pkg.equals(className.substring(0, className.lastIndexOf('.'))))) {
ourFiles.add(entry.getValue());
}
}
if(ourFiles.size() > 0) {
for(JavaFileObject javaFileObject : superFiles) {
ourFiles.add(javaFileObject);
}
return ourFiles;
}
}
// nothing found in our hash map that matches the criteria... return
// whatever super came up with.
return superFiles;
}
一旦你正确实施了这些方法,剩下的就行了。享受!
答案 1 :(得分:1)
这导致了一个明显的问题,即为什么要先分别编译A类。为什么不一次编译所有内容?
答案 2 :(得分:0)
如果保持文件的修改时间和(内存中)编译的字节代码怎么办?
答案 3 :(得分:0)
我认为你不能避免编译这两个类。事实上,如果你不编译它们,你可能会遇到二进制兼容性问题,或者内联常量不正确的问题。
如果您从命令行编译了一个类而不是另一个类,那么这个问题基本上是相同的。
但说实话,我不会担心尝试优化这样的编译。 (如果您的应用程序需要能够动态编译一个类而不是另一个类,则可能存在重大的设计问题。)