支持Java Compiler API中仅清单jar

时间:2012-06-13 19:19:34

标签: java compilation manifest javac manifest.mf

Java Compiler API是否支持类路径参数中包含Class-Path条目的仅清单jar文件?

我正在尝试在Maven Surefire测试中使用Java Compiler API,但似乎Java Compiler API,或更确切地说是ToolProvider.getSystemJavaCompiler(),不能正确处理Surefire的仅清单jar。

以下是显示失败测试的代码段

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

1 个答案:

答案 0 :(得分:2)

我遇到了类似的问题,在surefire单元测试中使用jsp编译运行嵌入式jetty。更简单的解决方案是将surefire插件配置为不使用仅清单jar

  <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("(?<!\\\\) "));
}