Как динамически скомпилировать и запустить файл. java с файлом .class в ресурсе? - PullRequest
0 голосов
/ 13 апреля 2020

Я пытаюсь заставить мой класс Main распечатать на своей консоли (eclipse) вывод из класса Example1 (в файле resources / as. java), который зависит от класса Example2. У меня была эта идея для целей оценки - реализовать ее в приложении javafx, которое запускает тестовый класс (Example1) для скомпилированного файла класса, найденного с помощью FileChooser. Я узнал об использовании JavaCompiler, но не мог понять, как его использовать для компиляции файла. java с зависимостью от файла .class и его выполнения ...

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 как . java файл в resources/Example1.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 как файл .class в resources/Example2.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;
    }
}

1 Ответ

1 голос
/ 13 апреля 2020

Путь к классу должен называть папку, содержащую Example2.class, а не само имя файла, поэтому измените второе tag.add(...) на tag.add("resources").

Вам нужно вызвать task.call(), чтобы фактически выполнить компилятор , Затем компилятор поместит файл Example1.class рядом с файлом Example1.java.

Чтобы запустить класс, вам нужно настроить ClassLoader с папкой resources в пути к классам, а затем использовать отражение чтобы получить класс Example1 и его метод main.

StandardJavaFileManager и URLClassLoader оба являются ресурсами , поэтому вы должны использовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...