在Eclipse与Maven中的Tomcat中使用JavaCompiler使用webapp类路径

时间:2013-06-02 20:36:18

标签: eclipse maven tomcat classpath java-compiler-api

我有一个使用Maven引用“示例库”的现有“示例Webapp”。我正在使用m2e插件在Eclipse 4.3RC3中运行Tomcat 7。当我在Eclipse内部的Tomcat上启动Example Webapp时,我已经验证example-library.jar可能已部署在Tomcat实例的WEB-INF/lib文件夹中。

示例Webapp具有使用JavaCompiler.CompilationTask动态编译某些类的代码。这些动态生成的类引用example-library.jar中的类。不幸的是,编译任务失败了,因为找不到引用的类。

我知道我可以set the JavaCompiler classpath,但System.getProperty("java.class.path")只返回Tomcat类路径,而不是webapp类路径:

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中的jar,但当我将其作为{{1}提供时-classpath的选项,任务仍然失败,因为它找不到引用的类。

如何简单地将当前正在执行的代码的类路径提供给compiler.getTask()实例,以便它可以从JavaCompiler中的库中找到类? (similar question引发了{{3}}但从未回答有关使用WEB-INF/lib引用ear文件中的jar文件的问题。)

示例:为了不惜任何代价让事情变得有效,我甚至尝试对类路径进行硬编码。例如,我的webapp lib目录中有JavaCompiler,所以我使用了以下代码,根据我上面指出的答案进行了修改:

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(); success,我的false表示diaognostics,即使该包位于package com.example.foo.bar does not exist...

3 个答案:

答案 0 :(得分:1)

将example-library.jar放在文件系统中的某个位置,并将该位置传递给运行JavaCompiler的代码(-classpath选项)。如果使用爆炸的WAR文件进行部署,您当然可以将其指向WEB-INF / lib文件夹中的物理位置。关键是您只需要在webapp中使用一个可配置参数来执行此操作,这可以是属性文件条目,-D系统属性,数据库行或其他完全。

示例代码(在Tomora 7和Fedora 18 x64上的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];
}

有关可运行的示例网络应用,请参阅https://github.com/jpalomaki/compiler

答案 1 :(得分:0)

我遇到了同样的问题。原因不是&#34; -classpath&#34;

我的代码:

   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。

答案 2 :(得分:0)

您可以按照提供的答案提供更具体的问题,即如何从直接从未扩展的WAR文件运行的Web应用程序中加载已编译代码的依赖关系(没有要引用的JAR文件 - 只有容器&#39; s class loder知道如何访问类):https://stackoverflow.com/a/45038007/2546679