CompilationTask.call()引入了ClassNotFoundException.曾在JDK6工作,未在J



从JDK6移动到JDK7后,下一个代码失败,出现ClassNotFoundException

CompilationTask task = cSysCompiler.getTask(null, cFileManager, cDiagnosticCollector, null, null, cUnitsToCompile);
boolean mSuccess = task.call();
Analyzer mAnalyzer = new Analyzer(); // Throws ClassNotFoundException

解决方法:

ClassLoader mSystemClassLoader = ClassLoader.getSystemClassLoader();
mSystemClassLoader.loadClass("ft.jopc.com.JavaBytecodeObject");
mSystemClassLoader.loadClass("ft.jopc.com.analyzer.Analyzer");
mSystemClassLoader.loadClass("ft.jopc.opccl.ClassLoaderListener");
…
ompilationTask task = cSysCompiler.getTask(null, cFileManager, cDiagnosticCollector, null, null, cUnitsToCompile);
boolean mSuccess = task.call();
Analyzer mAnalyzer = new Analyzer(); // No ClassNotFoundException

有人知道为什么在调用task.call()之后再也找不到类了吗?看起来系统类加载器在某种程度上被编译任务更改了?

我们最近遇到了一个类似的问题,JavaFileManager的自定义实现重新定义了

public ClassLoader getClassLoader(final Location location)
{
return getClass().getClassLoader();
}

不知道为什么要这样做,但就像你的情况一样,这在jdk6下运行得很好。我们指出了这个函数的jdk7问题,部分原因是它在单元测试中失败了(类加载器是Launcher$AppClassLoader),但在"生产模式"中运行良好(类由自定义类加载器加载)。更改此函数以使用StandardFileManager版本,甚至只是将其封装在一个空的URLClassloader中,例如

return new URLClassLoader(new URL[]{}, getClass().getClassLoader());

修复了问题。

显然,这与URLClassloader的引入有关,因此AppClassLoader在jdk7中是"可关闭的",如所示

Thread [main] (Suspended (breakpoint at line 282 in URLClassLoader))    
Launcher$AppClassLoader(URLClassLoader).close() line: 282 [local variables unavailable] 
JavacProcessingEnvironment.close() line: 1257   
JavaCompiler.initProcessAnnotations(Iterable<Processor>) line: 1004 
JavaCompiler.compile(List<JavaFileObject>, List<String>, Iterable<Processor>) line: 821 
Main.compile(String[], String[], Context, List<JavaFileObject>, Iterable<Processor>) line: 439  
JavacTaskImpl.call() line: 132  

然后,我必须承认,我觉得javadoc在这个主题上并不是很清楚,但看看jdk6 DefaultFileManager和jdk7 BaseFileManager,很明显,我们的期望是提供一个临时文件管理器(因此需要关闭"如果可能的话"),而不是"通用"文件管理器。

(在任何情况下,我都很乐意了解有关该主题的其他/最佳实践参考资料)

相关内容

最新更新