4

Java コンパイラ APIClass-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");
    }
4

1 に答える 1

2

確実な単体テスト内でjspコンパイルを使用して組み込みのjettyを実行すると、同様の問題が発生しました。より簡単な解決策は、マニフェストのみの 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("(?<!\\\\) "));
}
于 2012-10-11T09:14:47.717 に答える