java - 如何动态编译和运行资源中带有.class文件的.java文件?

标签 java javacompiler

我试图让我的主类在其控制台(eclipse)中打印出依赖于Example2类的Example1类(在resources/中作为.java文件)的输出。我出于评分目的有了这个想法 - 在 javafx 应用程序中实现它,该应用程序在使用 FileChooser 找到的编译类文件上运行测试类(示例 1)。我发现了使用 JavaCompiler,但我不知道如何使用它来编译依赖于 .class 文件的 .java 文件并执行它...

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class Main {
    private static final String EXAMPLE1 = "resources/Example1.java";
    private static final String EXAMPLE2 = "resources/Example2.class";

    public static void main(String[] args) {

        JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> d = new DiagnosticCollector<>();
        StandardJavaFileManager fm = jc.getStandardFileManager(d, null, null);

        List<String> tag = new ArrayList<>();
        tag.add("-classpath");
        tag.add(System.getProperty("java.class.path") + File.pathSeparator + EXAMPLE2);

        File file = new File(EXAMPLE1);
        Iterable<? extends JavaFileObject> cu = fm.getJavaFileObjectsFromFiles(Arrays.asList(file));
        JavaCompiler.CompilationTask task = jc.getTask(null, fm, null, tag, null, cu);

        /*
         * ?
         */
    }
}

Example1 作为 resources/Example1.java 中的 .java 文件。

public class Example1 {
    public static void main(String[] args) {
        Example2 ex2 = new Example2(1, 2);
        System.out.println("x : " + ex2.x + ", y : " + ex2.y);
        System.out.println("sum : " + ex2.sum());
        System.out.println("mult : " + ex2.mult());
    }
}

Example2 作为 resources/Example2.class 中的 .class 文件

public class Example2 {
    int x;
    int y;

    Example2(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int sum() {
        return x + y;
    }

    public int mult() {
        return x * y;
    }
}

最佳答案

类路径必须命名包含 Example2.class 的文件夹,而不是文件名本身,因此将第二个 tag.add(...) 更改为 tag.add("资源").

您需要调用task.call()来实际执行编译器。然后,编译器会将 Example1.class 文件放置在 Example1.java 文件旁边。

要运行该类,您需要在类路径中的 resources 文件夹中设置一个 ClassLoader,然后使用反射来获取 Example1类及其 main 方法。

StandardJavaFileManagerURLClassLoader 都是资源,因此您应该在完成后使用 try-with-resources 来正确关闭它们他们。

这是工作代码:

JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> d = new DiagnosticCollector<>();
try (StandardJavaFileManager fm = jc.getStandardFileManager(d, null, null)) {

    List<String> tag = new ArrayList<>();
    tag.add("-classpath");
    tag.add("resources");

    File file = new File(EXAMPLE1);
    Iterable<? extends JavaFileObject> cu = fm.getJavaFileObjectsFromFiles(Arrays.asList(file));
    JavaCompiler.CompilationTask task = jc.getTask(null, fm, null, tag, null, cu);
    if (! task.call())
        throw new IllegalStateException("compilation failed");
}

try (URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { new File("resources").toURI().toURL() })) {
    Class<?> example1Class = Class.forName("Example1", true, classLoader);
    Method mainMethod = example1Class.getMethod("main", String[].class);
    if (! Modifier.isStatic(mainMethod.getModifiers()))
        throw new IllegalStateException("main method is not static");
    mainMethod.invoke(null, (Object) new String[0]);
}

如果 Example1.java 中存在错误,您将得到如下 STDERR 输出:

resources\Example1.java:3: error: cannot find symbol
        xExample2 ex2 = new Example2(1, 2);
        ^
  symbol:   class xExample2
  location: class Example1
1 error
Exception in thread "main" java.lang.IllegalStateException: compilation failed
    at Test.main(Test.java:32)

如果类可以编译,并且具有正确的名称和方法,则 STDOUT 输出将为:

x : 1, y : 2
sum : 3
mult : 2

关于java - 如何动态编译和运行资源中带有.class文件的.java文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61181143/

相关文章:

java - 定期扫描数据库表以查找新行

java - 如何使用 Zxing 创建自定义 View ?

java - 构造函数中的复杂初始化

java - 添加 "query.getResultList()"时编译器发出警告

JavaCompiler 并没有真正编译这个类

Java for 循环优化

java - 热衷于从 netsuite 获取最后修改的贷项凭证记录

java - 带有 java 和 groovy 源文件夹的 Maven 项目,如何在 POM 中表示

java - 即使编译器版本为 1.8,-source 1.5 也不支持菱形运算符

java - Java 8 中 try-with-resources block 中的锁风险