2013-06-02 69 views
4

我有一個使用Maven引用「Example Library」的現有「示例Webapp」。我使用m2e插件在Eclipse 4.3RC3內部運行Tomcat 7。當我在Eclipse內部的Tomcat上啓動示例Webapp時,我已驗證example-library.jar可能正在部署在Tomcat實例的WEB-INF/lib文件夾中。在Maven中使用Tomcat中的Tomcat中的JavaCompiler使用webapp classpath

示例Web應用程序具有使用JavaCompiler.CompilationTask即時編譯某些類的代碼。這些動態生成的類引用example-library.jar中的類。不幸的是編譯任務失敗,因爲無法找到引用的類。

我知道我可以set the JavaCompiler classpath,但System.getProperty("java.class.path")只返回我Tomcat的類路徑,而不是Web應用程序類路徑:

C:\bin\tomcat\bin\bootstrap.jar;C:\bin\tomcat\bin\tomcat-juli.jar;C:\bin\jdk6\lib\tools.jar 

其他有said,我需要從servlet上下文得到的WEB-INF/lib真實路徑,但類生成代碼並不知道關於servlet上下文的任何信息---它被寫成不知道它是在客戶端還是在服務器上使用。

another question,一個answer表示我可以列舉的類加載器的網址,果然這爲我提供了的罐子在WEB-INF/lib,但是當我提供這作爲-classpath選項compiler.getTask(),任務仍然失敗,因爲它不能找到引用的類。

如何簡單地將當前正在執行的代碼的類路徑提供給JavaCompiler實例,以便它可以從WEB-INF/lib的庫中找到類? (A similar question升高而對於使用JavaCompiler引用耳朵文件中的罐子根本沒有回答。)

例子:在試圖得到的東西,不惜任何代價的工作,我甚至嘗試硬編碼的類路徑。例如,我在我的web應用lib目錄foobar.lib,所以用下面的代碼,來自我上面所指出的問題的答案修改:

List<String> options = new ArrayList<String>(); 
options.add("-classpath"); 
options.add("C:\\work\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp0\\wtpwebapps\\FooBar\\WEB-INF\\lib\\foobar.jar"); 
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits); 
boolean success = task.call(); 

在端successfalse,我的diaognostics表示package com.example.foo.bar does not exist...,即使該包在foobar.jar

回答

1

將example-library.jar放入文件系統的某個位置,並將該位置傳遞給運行JavaCompiler的代碼(-classpath選項)。如果您使用展開的WAR文件進行部署,則當然可以將其指向WEB-INF/lib文件夾中的物理位置。重點是你只需要在你的webapp中有一個可配置的參數來做到這一點,它可以是一個屬性文件入口,-D系統屬性,數據庫行或其他東西。

示例代碼(在Fedora 18 64 Tomcat中7和OpenJDK的1.7測試):

private File compile(File javaFile, String classpath) throws IOException { 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); 
    Iterable<? extends JavaFileObject> compilationUnit = fileManager.getJavaFileObjects(javaFile); 
    List<String> options = classpath != null ? Arrays.asList("-classpath", classpath) : null; 
    StringWriter output = new StringWriter(); 
    try { 
     boolean successful = compiler.getTask(output, fileManager, null, options, null, compilationUnit).call(); 
     if (!successful) { 
      throw new CompilationException("Failed to compile: " + javaFile, output.toString()); 
     } 
     return firstClassFileFrom(javaFile.getParentFile()); 
    } finally { 
     fileManager.close(); 
    } 
} 

private File firstClassFileFrom(File directory) { 
    return directory.listFiles(new FilenameFilter() { 
     @Override 
     public boolean accept(File dir, String name) { 
      return name.endsWith(".class"); 
     } 
    })[0]; 
} 

爲可運行的web應用樣品參見https://github.com/jpalomaki/compiler

+0

您是否仔細閱讀過我的問題以及我提供的鏈接?你的答案與我已經嘗試的方法有什麼不同,而且提供了實際的代碼? –

+0

是的,我的確看過你的問題。您提供了一個指向stackoverflow答案的鏈接,向您展示瞭如何設置JavaCompiler -classpath,然後您問「如何簡單地向JavaCompiler提供當前正在執行的代碼的類路徑」。現在只需創建classpath字符串(例如/path/to/webapp/WEB-INF/lib/example-library.jar)並將其傳遞給javaCompiler。您的組件無需瞭解有關Servlet上下文或類加載器URL的任何信息。 – Jukka

+0

我已經嘗試過了,並且不起作用。我已經更新了這個問題,以包含我嘗試過的一個例子。也許你可以指出我做錯了什麼。 –

0

我遇到了同樣的問題。原因不是「-classpath」。

我的代碼:

String classpath ="xx/WEB-INF/clases "; 
    List<String> options = classpath != null ? Arrays.asList("-d", classpath,"-cp",classpath) : null; 
    CompilationTask task = compiler.getTask(null, javaDinamicoManager, diagnostics, 
      options, null, Arrays.asList(sourceObj)); 
    boolean result = task.call(); 

的「結果」將返回true。

0

您可以按照提供的答案提供更具體的問題,以瞭解如何從直接從未展開WAR文件運行的Web應用程序中加載編譯代碼的依賴關係(沒有要引用的JAR文件 - 只有容器的類代碼知道如何進入課程):https://stackoverflow.com/a/45038007/2546679