How do you dynamically compile and load external java classes? [duplicate]
Как вы динамически компилируете и загружаете внешние классы Java?
(Этот вопрос похож на многие вопросы, которые я видел, но большинство из них недостаточно конкретны для того, что я делаю)
Справочная информация:
Цель моей программы - упростить для людей, использующих мою программу, создание пользовательских, так сказать, "плагинов", а затем скомпилировать и загрузить их в программу для использования (по сравнению с неполным и медленным анализатором, реализованным в моей программе). Моя программа позволяет пользователям вводить код в заранее определенный класс, расширяющий скомпилированный класс, входящий в комплект моей программы. Они вводят код в текстовые области, затем моя программа копирует код в переопределяемые методы. Затем это сохраняется как файл .java (почти) готовый для компиляции. Программа запускает javac (компилятор Java) с сохраненным файлом .java в качестве входных данных.
Мой вопрос в том, как мне сделать так, чтобы клиент мог (используя мою скомпилированную программу) сохранить этот java-файл (который расширяет мой InterfaceExample) в любом месте на своем компьютере, чтобы моя программа скомпилировала его (не говоря "не удается найти symbol: InterfaceExample"), затем загрузить его и вызвать метод doSomething()?
Я продолжаю видеть вопросы и ответы, использующие reflection или ClassLoader, и один, в котором почти описано, как его скомпилировать, но ни один из них не является достаточно подробным для меня / я не понимаю их полностью.
// This sets up the class path that the compiler will use. // I've added the .jar file that contains the DoStuff interface within in it... List<String> optionList = newArrayList<String>(); optionList.add("-classpath"); optionList.add(System.getProperty("java.class.path") + File.pathSeparator + "dist/InlineCompiler.jar");
Iterable<? extendsJavaFileObject> compilationUnit = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(helloWorldJava)); JavaCompiler.CompilationTasktask= compiler.getTask( null, fileManager, diagnostics, optionList, null, compilationUnit); /********************************************************************************************* Compilation Requirements **/ if (task.call()) { /** Load and execute *************************************************************************************************/ System.out.println("Yipe"); // Create a new custom class loader, pointing to the directory that contains the compiled // classes, this should point to the top of the package structure! URLClassLoaderclassLoader=newURLClassLoader(newURL[]{newFile("./").toURI().toURL()}); // Load the class from the classloader by name.... Class<?> loadedClass = classLoader.loadClass("testcompile.HelloWorld"); // Create a new instance... Objectobj= loadedClass.newInstance(); // Santity check if (obj instanceof DoStuff) { // Cast to the DoStuff interface DoStuffstuffToDo= (DoStuff)obj; // Run it baby stuffToDo.doStuff(); } /************************************************************************************************* Load and execute **/ } else { for (Diagnostic<? extendsJavaFileObject> diagnostic : diagnostics.getDiagnostics()) { System.out.format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource().toUri()); } } fileManager.close(); } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) { exp.printStackTrace(); } } }
publicstaticinterfaceDoStuff {
publicvoiddoStuff(); }
}
Теперь обновлено, чтобы включать добавление пути к классу для компилятора, а также загрузку и выполнение скомпилированного класса!
Ответ 2
Я предлагаю использовать библиотеку Java Runtime Compiler. Вы можете предоставить ему строку в памяти, и он скомпилирует и загрузит класс в текущий загрузчик классов (или в один по вашему выбору) и вернет загруженный класс. Вложенные классы также загружаются. Примечание: по умолчанию это работает полностью в памяти.
например
// dynamically you can call StringclassName="mypackage.MyClass"; StringjavaCode="package mypackage;\n" + "public class MyClass implements Runnable {\n" + " public void run() {\n" + " System.out.println(\"Hello World\");\n" + " }\n" + "}\n"; ClassaClass= CompilerUtils.CACHED_COMPILER.loadFromJava(className, javaCode); Runnablerunner= (Runnable) aClass.newInstance(); runner.run();