java类加载器和运行时编译
尽管有人警告我放弃目前的做法,但我目前看不到更好的办法来解决我的问题。我必须在运行时生成Java代码,然后编译、加载并引用它 问题是生成的代码导入的代码已经由系统类加载器(我想)加载——也就是说,存在于我的类路径上的一个JAR中的代码。 (我在Java 6上的Tomcat 6 web容器中运行。)你们可能会问自己,为什么这是一个问题——我当然不知道——但事实是,我会遇到编译错误: /W:/…/parser/v0.5/AssignELParser.java:6: 包com.xxx.yyy.zzz.configuration 不存在 根据互联网上的一些示例,我定义了以下类:java类加载器和运行时编译,java,compiler-construction,code-generation,runtime,classloader,Java,Compiler Construction,Code Generation,Runtime,Classloader,尽管有人警告我放弃目前的做法,但我目前看不到更好的办法来解决我的问题。我必须在运行时生成Java代码,然后编译、加载并引用它 问题是生成的代码导入的代码已经由系统类加载器(我想)加载——也就是说,存在于我的类路径上的一个JAR中的代码。 (我在Java 6上的Tomcat 6 web容器中运行。)你们可能会问自己,为什么这是一个问题——我当然不知道——但事实是,我会遇到编译错误: /W:/…/parser/v0.5/AssignELParser.java:6: 包com.xxx.yyy.zzz.
class MemoryClassLoader extends ChainedAction {
private static final Logger LOG = Logger.getLogger(MemoryClassLoader.class);
private LoaderImpl impl;
private class LoaderImpl extends ClassLoader {
// The compiler tool
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// Compiler options
private final Iterable<String> options = Arrays.asList("-verbose");
// DiagnosticCollector, for collecting compilation problems
private final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
// Our FileManager
private final MemoryFileManager manager = new MemoryFileManager(this.compiler);
public LoaderImpl(File sourceDirectory) {
List<Source> list = new ArrayList<Source>();
File[] files = sourceDirectory.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(Kind.SOURCE.extension);
}
});
for (File file : files) {
list.add(new Source(file));
}
CompilationTask task = compiler.getTask(null, manager, diagnostics, options, null, list);
Boolean compilationSuccessful = task.call();
LOG.info("Compilation has " + ((compilationSuccessful) ? "concluded successfully" : "failed"));
// report on all errors to screen
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
LOG.warn(diagnostic.getMessage(null));
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
synchronized (this.manager) {
Output output = manager.map.remove(name);
if (output != null) {
byte[] array = output.toByteArray();
return defineClass(name, array, 0, array.length);
}
}
return super.findClass(name);
}
}
@Override
protected void run() {
impl = new LoaderImpl(new File(/* Some directory path */));
}
}
class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
final Map<String, Output> map = new HashMap<String, Output>();
MemoryFileManager(JavaCompiler compiler) {
super(compiler.getStandardFileManager(null, null, null));
}
@Override
public Output getJavaFileForOutput(Location location, String name, Kind kind, FileObject source) {
Output output = new Output(name, kind);
map.put(name, output);
return output;
}
}
class Output extends SimpleJavaFileObject {
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
Output(String name, Kind kind) {
super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind);
}
byte[] toByteArray() {
return this.baos.toByteArray();
}
@Override
public ByteArrayOutputStream openOutputStream() {
return this.baos;
}
}
class Source extends SimpleJavaFileObject {
public Source(File file) {
super(file.toURI(), Kind.SOURCE);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
StringBuilder sb = new StringBuilder("");
try {
File file = new File(uri);
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
sb = new StringBuilder((int) file.length());
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sb.toString();
}
}
类MemoryClassLoader扩展了ChainedAction{
私有静态最终记录器LOG=Logger.getLogger(MemoryClassLoader.class);
私有装入器impl;
私有类装入器Impl扩展了类装入器{
//编译工具
私有最终JavaCompiler编译器=ToolProvider.getSystemJavaCompiler();
//编译器选项
private final Iterable options=Arrays.asList(“-verbose”);
//DiagnosticCollector,用于收集编译问题
专用最终DiagnosticCollector diagnostics=新DiagnosticCollector();
//我们的文件管理器
私有最终MemoryFileManager=新MemoryFileManager(this.compiler);
公共LoaderImpl(文件源目录){
列表=新的ArrayList();
File[]files=sourceDirectory.listFiles(新文件名过滤器(){
@凌驾
公共布尔接受(文件目录,字符串名称){
返回name.endsWith(Kind.SOURCE.extension);
}
});
用于(文件:文件){
添加(新源(文件));
}
CompilationTask=compiler.getTask(null、管理器、诊断、选项、null、列表);
布尔编译成功=task.call();
LOG.info(“编译已”+((compilationSuccessful)?“成功结束”:“失败”);
//向屏幕报告所有错误
对于(诊断不确定是否有帮助,但您是否尝试显式指定类路径
getClassPath()
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL[] urls = ((URLClassLoader) classLoader).getURLs();
StringBuilder buf = new StringBuilder(1000);
buf.append(".");
String separator = System.getProperty("path.separator");
for (URL url : urls) {
buf.append(separator).append(url.getFile());
}
}
classPath = buf.toString();
然后
options.add("-classpath");
options.add(getClassPath());
我也看不出你在哪里把LoaderImpl
实例传递给编译器
。难道不应该显式传递吗
getClassPath()
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL[] urls = ((URLClassLoader) classLoader).getURLs();
StringBuilder buf = new StringBuilder(1000);
buf.append(".");
String separator = System.getProperty("path.separator");
for (URL url : urls) {
buf.append(separator).append(url.getFile());
}
}
classPath = buf.toString();