0

从 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() 类之后找不到了?编译任务似乎以某种方式更改了系统类加载器?

4

1 回答 1

3

我们最近在重新定义 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,似乎很清楚期望是提供一个临时文件管理器(因此需要关闭“如果可能”)而不是“通用用途”。

(无论如何,我很乐意了解有关该主题的其他/最佳实践参考)

于 2013-02-19T15:38:18.050 回答