2012-06-13 47 views
4

Java編譯器API是否支持在類路徑參數中使用Class-Path條目的僅清單jar文件?支持Java編譯器API中的僅清單jar文件

我想在Maven Surefire測試中使用Java編譯器API,但似乎Java編譯器API或更確切地說是ToolProvider.getSystemJavaCompiler()不能正確處理純淨的Surefire罐子。

下面的代碼片段顯示一個失敗的測試

new File("target/out").mkdir(); 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    URLClassLoader classLoader = (URLClassLoader)Thread.currentThread().getContextClassLoader(); 

    // create classpath 
    StringBuilder path = new StringBuilder(); 
    for (URL url : ((URLClassLoader) classLoader).getURLs()) { 
     if (path.length() > 0) { 
      path.append(File.pathSeparator); 
     } 
     String decodedPath = URLDecoder.decode(url.getPath(), "UTF-8"); 
     path.append(new File(decodedPath).getAbsolutePath()); 
    } 
    System.err.println(path); 

    // compile 
    List<String> options = Arrays.asList(
     "-classpath", path.toString(),  
     "-s", "target/out", 
     "src/test/java/com/mysema/codegen/SimpleCompilerTest.java"); 
    int compilationResult = compiler.run(null, null, null, 
      options.toArray(new String[options.size()])); 
    if (compilationResult != 0) { 
     Assert.fail("Compilation Failed"); 
    } 
+0

你可以發佈一個小代碼示例,顯示你正在嘗試做什麼以及它如何失敗?非常有趣的問題? –

+0

增加了一些測試代碼 –

回答

2

我跑進運行萬無一失的單元測試與內部JSP編譯嵌入碼頭類似的問題。在簡單的解決方案是配置萬無一失插件不使用清單隻罐子

<plugin> 
    <artifactId>maven-surefire-plugin</artifactId> 
    <configuration> 
     <useManifestOnlyJar>false</useManifestOnlyJar> 
    </configuration> 
    </plugin> 

更難的解決辦法是擴大類路徑,包括從清單類路徑引用的jar文件字段

static List<String> getClassPathForJspCompiler() throws IOException { 
    List<String> classPath = Lists.newArrayList(System.getProperty("java.class.path") 
      .split(File.pathSeparator)); 
    return expandManifestClassPathElements(classPath); 
} 

private static List<String> expandManifestClassPathElements(List<String> classPath) 
     throws IOException { 
    for (int i = 0; i < classPath.size(); i++) { 
     String element = classPath.get(i); 
     if (element.endsWith(".jar")) { 
      for (String manifestElement : getManifestClassPath(element)) { 
       // add to the end of the class path so it will get processed 
       if (!classPath.contains(manifestElement)) { 
        // only add if not already present to prevent cyclic loop 
        classPath.add(manifestElement); 
       } 
      } 

     } 
    } 
    return classPath; 
} 

private static List<String> getManifestClassPath(String jarFilePath) throws IOException { 
    File jarFile = new File(jarFilePath); 
    if (!jarFile.isFile()) { 
     return ImmutableList.of(); 
    } 
    Manifest manifest = new JarFile(jarFile).getManifest(); 
    if (manifest == null) { 
     return ImmutableList.of(); 
    } 
    String manifestClassPath = manifest.getMainAttributes().getValue(
      Attributes.Name.CLASS_PATH); 
    if (manifestClassPath == null) { 
     return ImmutableList.of(); 
    } 
    // split at all spaces that are not preceded by a backslash 
    return Lists.newArrayList(manifestClassPath.split("(?<!\\\\) ")); 
}