gpt4 book ai didi

java类加载器和运行时编译

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:27:32 24 4
gpt4 key购买 nike

尽管警告要我放弃目前的做法,但我目前看不到更好的方法来解决我的问题。我必须 生成 在运行时运行 Java 代码,然后编译它、加载它并引用它

问题是生成的代码导入了系统类加载器已经加载的代码(我想)——也就是说,代码存在于我的类路径中的一个 jar 中。(我在 Java 6 上的 Tomcat 6 Web 容器中运行。)您可能会问自己为什么这是个问题 - 好吧肯定不知道 - 但事实是我遇到了编译错误:

/W:/.../parser/v0.5/AssignELParser.java:6: package com.xxx.yyy.zzz.configuration does not exist

根据互联网上的一些示例,我定义了以下类:

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();
}
}

似乎通过扩展 ClassLoader 类而不调用显式 super 构造函数的内部类 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();

然后

options.add("-classpath");
options.add(getClassPath());

我也看不到你在哪里将 LoaderImpl 实例传递给 compiler。不应该明确地完成吗?

关于java类加载器和运行时编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1642606/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com