10

我知道這已被問及很多回答,但我仍然沒有一個好的解決方案,我仍然不理解某些部分。所以我有要求以編程方式編譯* .java文件。以編程方式編譯java文件

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 

是我正在使用和(如預期的)編譯器是null。 現在,我知道我必須使用JDK而不是JRE來作爲「運行時」,但這裏有一些我不明白的地方:僅僅將tools.jar放在應用程序的類路徑中是不夠的,然後有權訪問Java編譯器API?如果這是真的,那麼獨立的java應用程序和基於web的應用程序是否存在(我認爲是有區別的)。其實,我試圖從PlayFramework webapp召集JavaCompiler,所以我想通了,也許這個解決方案(包括tools.jar)只適用於獨立應用程序?

我也嘗試創建一個定製的ClassLoader,並調用與反射上述方法,但所有我得到的是nullcompiler對象:

ClassLoader classloader = app.classloader(); 
File file = new File("lib/tools.jar");   
URL url = file.toURI().toURL(); 
URL[] urls = new URL[]{url}; 
ClassLoader newCL = new URLClassLoader(urls, classloader) { 
}; 
Class<?> loadClass = newCL.loadClass("javax.tools.ToolProvider"); 
Method method = loadClass.getMethod("getSystemJavaCompiler", null);    
Object object = method.invoke(null); 
System.out.println("Object: " + object); // NULL 

解釋上面的代碼:

  • 爲了簡單起見,我沒有包含try/catches。
  • app.classloader()是一個播放方法,它返回的應用
  • tools.jar的類加載器包含在我的lib中的播放項目(這意味着它是在項目的類路徑的文件夾 - 根據播放文件)

我非常肯定還有其他事情我需要做之前播放能夠加載Java編譯器類我只是不知道我缺少什麼。

Runtime.exec("javac myFile.java")和Eclipse JDT編譯器之類的選項對我而言是已知的,但這不是我所期待的。

哦,和System.setProperty("java.home", "PATH_TO_YOUR_JDK");之類的東西,然後ToolProvider.getSystemJavaCompiler();正在工作,但我覺得這個解決方案如此醜陋。

問候

編輯:(提供其他信息,並反映過去的狀況) 這是web應用程序結構的基本表示:

myApp 
|-conf\... 
|-lib\MyJar.jar 
|-lib\tools.jar 
|-logs\... 
|-... 

MyJar.jar已現一個META-INF/MANIFEST.MF文件包含以下內容:

Manifest-Version: 1.0 
Sealed: true 
Main-Class: here.comes.my.main.class 
Class-Path: tools.jar 

沒有啓動Play應用程序,我試圖(在lib文件夾中):java -jar MyJar.jar - 我的簡單main方法嘗試調用編譯器(ToolProvider.getSystemJavaCompiler();)並返回null。所以這讓我相信,這個問題與Play無關 - 在正常運行我的Jar時我甚至無法獲得編譯器!

回答

0

它說在documentationTo run the Play framework, you need JDK 6 or later.你是怎麼設法用jre運行的?

無論如何,如果getSystemJavaCompiler返回null,這意味着您的類路徑中沒有tools.jar或者它已損壞。如果是Sun/Oracle Java,請確保它有com.sun.tools.javac.api.JavacTool類。

如果你想使用自定義的類裝載器,您需要加載,不ToolProvider的JavacTool類。看看它的方式,以便在Java 6:

 URL[] urls = {file.toURI().toURL()}; 
     ClassLoader cl = URLClassLoader.newInstance(urls); 
     cl.setPackageAssertionStatus("com.sun.tools.javac", true); 
     return Class.forName(defaultJavaCompilerName, false, cl); 

其中defaultJavaCompilerName = "com.sun.tools.javac.api.JavacTool"

子類它JavaCompiler並獲得新的實例 - 你有你的編譯器。

+0

'JAVA_HOME'設置我的開發機器上,當被問及對路徑返回到JDK。但是,運行Play應用程序(使用'System.getProperty(...)')獲取''java.home''屬性將返回JRE的路徑。所以也許那是一個問題。但是當我在我的類路徑中有'tools.jar'時應該沒有問題。我非常確定'tools.jar'在我的類路徑中(在運行Web應用程序時檢查它),並且文件沒有被破壞。我將嘗試上面提到的類加載的東西。 – user2229298

+0

我在我的Ubuntu上運行,我可以從scala動作獲得java編譯器,沒有任何問題。也許你的設置有問題嗎? –

+0

剛剛嘗試過'JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();在應用程序的類路徑中使用'tools.jar',System.out.println(「Java compiler:」+ javaCompiler);''從app/Global.java中的'onStart'方法獲得''''即使是返回'null' – user2229298

1

有Web應用程序和獨立應用程序之間沒有什麼區別。

你不應該打包成的tools.jar你的web應用的classpath。 Java中的類加載器通常只能自下而上。因此,作爲jdk一部分的ToolProvider將不會在webapp類路徑中看到您的tools.jar(它不能查看webapp類路徑)。

解決方案:使用JDK,並確保您指向它或將在的tools.jar的Java的EXT目錄。您可以通過將屬性-Djava.ext.dir設置爲您喜歡的任何目錄來覆蓋ext目錄。

+0

這聽起來不錯。我會建議把工具jar放在一個普通的地方或使用jdk。 – tgkprog