2011-08-21 51 views
1

我有一個像這樣的程序:它編譯內存中的文件,然後從內存中執行它們。因此,我需要一個帶文件管理器的自定義類加載器,它將文件存儲在備忘錄中://。 現在我想傳遞參數給編譯器輸出的類,因爲我認爲它不會繼承它們(-Xmx80M,-Djava.library.path等)。我想我會需要-J選項,但編譯器會返回IllegalArgumentExceptioncom.sun.tools.javac.main.RecognizedOptions.getJavacToolOptions(null)沒有列出-J要麼,所以我想我試圖把論點放在錯誤的地方。我應該在哪裏使用-J(或其他選項)的經驗?JavaCompiler API的選項

編輯:com.sun.tools.javac.main.RecognizedOptions.getAll(null)報告-J作爲一個選項,但是getJavacToolOptions(null)不會,也不getJavacFileManagerOptions(null)

爲了澄清,我想用(運行時)編譯代碼使用LWJGL庫。 LWJGL需要-Djava.library.path中的一些本機庫,它是爲該項目設置的。但是編譯後的代碼無法找到這個庫路徑。我認爲它不會繼承這個庫路徑,因此LWJGL會拋出一個NoClassDefFoundError。否則,它可能會將相關庫路徑解釋爲memo:// lib/lwjgl,但我無法檢查。

堆棧:

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庫加載額外的機庫 - 它不工作,我想。

定製類加載器: 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); 
    } 
} 

自定義文件管理:

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

您是否也從您的自定義類加載器加載OpenGL庫?如果是這樣,你可以嘗試讓它們從你的主類加載器加載(並指出它是你的主類加載器的父代)。 –

回答

3

如果您運行編譯器API,編譯器會在同一個虛擬機上運行的主程序,與共享內存它。

您正在編譯的類沒有任何這樣的設置 - 這些是Java VM的設置,不適用於任何類。 如果你想稍後在你的主程序中加載這些類,它們也將與你的主程序共享內存。

所以,我沒有看到使用這些參數的任何意義。

+0

這就是我最初的想法。但是-Djava.library.path在項目VM參數中設置正確,並且編譯後的代碼仍不會從路徑加載庫。對不起,如果我的措辭不正確。 – RobotRock

+0

這也應該起作用,但並不真正涉及到原始問題中的問題。 –

+0

但不幸的是它不起作用。我嘗試了完全相同的代碼,而沒有通過運行時編譯器運行,然後完美運行。我看起來很長,並在這裏找到了-J選項:http://download.oracle.com/javase/1.4.2/docs/tooldocs/windows/javac.html#options – RobotRock

2

你知道該課程使用哪個文件(dll)嗎?如果是這樣,請在編譯之前通過手動調用System.loadLibrary來解決此問題。

+0

我已經研究過這個,但是LWJGL有OS依賴庫,因此我更願意通過LWJGL處理這個問題,並且在未來更新的角度來看。 – RobotRock

+1

@Kaj Toet,然後調用'org.lwjgl.Sys.initialize()'。這樣更容易。 –

+0

哇,謝謝你的評論!這些庫很難被加載,因爲它們是32位庫。我使用的是舊的LWJGL,它沒有包含64位庫。 – RobotRock