JavaCompiler API 的选项

发布于 2024-11-30 17:09:53 字数 4751 浏览 2 评论 0原文

我有一个这样的程序:它在内存中编译文件,然后从内存中执行它们。因此,我需要一个带有文件管理器的自定义类加载器,该文件管理器将文件存储在 memo:// 中。 现在我想将参数传递给编译器输出的类,因为我认为它不会继承它们(-Xmx80M-Djava.library.path等)。我认为我需要 -J 选项,但是编译器返回一个 IllegalArgumentExceptioncom.sun.tools.javac.main.RecognizedOptions.getJavacToolOptions(null) 也没有列出 -J ,所以我想我正在尝试将争论在错误的地方。有什么地方应该使用 -J (或其他选项)的经验吗?

编辑:com.sun.tools.javac.main.RecognizedOptions.getAll(null)-J 报告为选项,但是 getJavacToolOptions(null ) 不会,getJavacFileManagerOptions(null) 也不会。

为了澄清,我想将 LWJGL 库与(运行时)编译的代码一起使用。 LWJGL 需要来自 -Djava.library.path 的一些本机库,这是为项目设置的。但是编译后的代码无法找到该库路径。我认为它不会继承这个库路径,因此 LWJGL 会抛出 NoClassDefFoundError。否则,它可能会将相对库路径错误解释为 memo://lib/lwjgl,但我无法检查。

Stack:

Aug 22, 2011 2:14:58 PM customcompile.CustomCompile$2 run
SEVERE: null
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at customcompile.CustomCompile$2.run(CustomCompile.java:90)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.lwjgl.Sys
    at org.lwjgl.opengl.Display.<clinit>(Display.java:111)
...

我还必须注意,项目包含的库已成功加载,但是 LWJGL 库加载了其他本机库 - 我认为这不起作用。

自定义类加载器: 打包自定义编译;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;

/**
 *
 * @author Kaj Toet
 */
class MemoryClassLoader extends ClassLoader {


    private JavaCompiler compiler;
    private final MemoryFileManager manager;

    public MemoryClassLoader(JavaCompiler compiler, String classname, String filecontent) {
        this(compiler, Collections.singletonMap(classname, filecontent));
    }

    public MemoryClassLoader(JavaCompiler compiler, Map<String, String> map) {
            this.compiler=compiler;

            DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

            manager  = new MemoryFileManager(this.compiler);
            List<Source> list = new ArrayList<Source>();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                list.add(new Source(entry.getKey(), Kind.SOURCE, entry.getValue()));
            }            

            List<String> optionList = new ArrayList<String>();
            // set compiler's classpath to be same as the runtime's
            //optionList.addAll(Arrays.asList("-cp", ".."));

            this.compiler.getTask(null, this.manager, diagnostics, optionList, null, list).call();
            for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
              CustomCompile.addDebugText(diagnostic.toString());
            }
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        synchronized (this.manager) {
            Output mc = this.manager.map.remove(name);
            if (mc != null) {
                byte[] array = mc.toByteArray();
                return defineClass(name, array, 0, array.length);
            }
        }
        return super.findClass(name);
    }
}

自定义文件管理器:

class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
    public 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 mc = new Output(name, kind);
        this.map.put(name, mc);
        return mc;
    }  
}

输出:

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

I have a program like this: it compiles files in memory and then executes them from memory. Therefore I needed a custom classloader with a file manager that stores files in memo://.
Now I want to pass parameters to the compilers outputted class, since I think it does not inherit them (-Xmx80M, -Djava.library.path etc.). I would think I would need the -J option for this, however the compiler returns an IllegalArgumentException. com.sun.tools.javac.main.RecognizedOptions.getJavacToolOptions(null) doesn't list -J either, so I'm thinking I'm trying to put the argument in the wrong place. Any experience with where I should use -J (or an other option for that matter)?

Edit: com.sun.tools.javac.main.RecognizedOptions.getAll(null) reports -J as an option, howevergetJavacToolOptions(null) does not, and neither getJavacFileManagerOptions(null).

To clarify, I want to use the LWJGL library with the (runtime)compiled code. LWJGL requires some native libraries from the -Djava.library.path, which is set for the project. However the compiled code is not able to find this library path. I'm thinking it does not inherit this library path, and therefor LWJGL throws a NoClassDefFoundError. Else, it might interpret the relative library path wrong as memo://lib/lwjgl, but I have no way to check.

Stack:

Aug 22, 2011 2:14:58 PM customcompile.CustomCompile$2 run
SEVERE: null
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at customcompile.CustomCompile$2.run(CustomCompile.java:90)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.lwjgl.Sys
    at org.lwjgl.opengl.Display.<clinit>(Display.java:111)
...

I also must note that libraries included by the project are loaded successfully, however the LWJGL library loads additional native libraries - which does not work I think.

Custom classloader:
package customcompile;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;

/**
 *
 * @author Kaj Toet
 */
class MemoryClassLoader extends ClassLoader {


    private JavaCompiler compiler;
    private final MemoryFileManager manager;

    public MemoryClassLoader(JavaCompiler compiler, String classname, String filecontent) {
        this(compiler, Collections.singletonMap(classname, filecontent));
    }

    public MemoryClassLoader(JavaCompiler compiler, Map<String, String> map) {
            this.compiler=compiler;

            DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

            manager  = new MemoryFileManager(this.compiler);
            List<Source> list = new ArrayList<Source>();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                list.add(new Source(entry.getKey(), Kind.SOURCE, entry.getValue()));
            }            

            List<String> optionList = new ArrayList<String>();
            // set compiler's classpath to be same as the runtime's
            //optionList.addAll(Arrays.asList("-cp", ".."));

            this.compiler.getTask(null, this.manager, diagnostics, optionList, null, list).call();
            for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
              CustomCompile.addDebugText(diagnostic.toString());
            }
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        synchronized (this.manager) {
            Output mc = this.manager.map.remove(name);
            if (mc != null) {
                byte[] array = mc.toByteArray();
                return defineClass(name, array, 0, array.length);
            }
        }
        return super.findClass(name);
    }
}

Custom filemanager:

class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
    public 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 mc = new Output(name, kind);
        this.map.put(name, mc);
        return mc;
    }  
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忆沫 2024-12-07 17:09:53

如果您运行编译器 API,编译器将在与主程序相同的 VM 中运行,并与其共享内存。

您正在编译的类没有任何此类设置 - 这些是 Java VM 的设置,而不是任何类的设置。
如果您想稍后在主程序中加载这些类,它们也将与您的主程序共享内存。

因此,我认为使用这些论点没有任何意义。

If you run the compiler API, the compiler will run in the same VM as your main program, sharing its memory with it.

The classes which you are compiling don't have any such settings - these are settings for the Java VM, not for any classes.
If you want to load these classes later in your main program, too, they will also share the memory with your main program.

So, I don't see any sense in using these arguments.

§对你不离不弃 2024-12-07 17:09:53

你知道该类使用哪个文件(dll)吗?如果这样做,请在进行编译之前尝试通过手动调用 System.loadLibrary 来解决该问题。

Do you know which file (dll) do the class use? If you do, try working around the problem by calling System.loadLibrary manually before you do your compile.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文