java - framework - jlabel definicion
¿Cómo compila y carga dinámicamente clases Java externas? (2)
Sugiero usar la biblioteca Java Runtime Compiler . Puede asignarle un String en la memoria y compilará y cargará la clase en el cargador de clases actual (o uno de su elección) y devolverá la clase cargada. Las clases anidadas también se cargan. Nota: esto funciona completamente en la memoria por defecto.
p.ej
// dynamically you can call
String className = "mypackage.MyClass";
String javaCode = "package mypackage;/n" +
"public class MyClass implements Runnable {/n" +
" public void run() {/n" +
" System.out.println(/"Hello World/");/n" +
" }/n" +
"}/n";
Class aClass = CompilerUtils.CACHED_COMPILER.loadFromJava(className, javaCode);
Runnable runner = (Runnable) aClass.newInstance();
runner.run();
Esta pregunta ya tiene una respuesta aquí:
(Esta pregunta es similar a muchas preguntas que he visto, pero la mayoría no son lo suficientemente específicas para lo que estoy haciendo)
Fondo:
El objetivo de mi programa es facilitarles a las personas que usan mi programa crear "complementos" personalizados, por así decirlo, luego compilarlos y cargarlos en el programa para su uso (frente a tener un analizador incompleto y lento implementado en mi programa). Mi programa permite a los usuarios ingresar código en una clase predefinida que extiende una clase compilada empaquetada con mi programa. Ingresan el código en paneles de texto y luego mi programa copia el código en los métodos que se anulan. A continuación, guarda esto como un archivo .java (casi) listo para el compilador. El programa ejecuta javac (compilador de Java) con el archivo .java guardado como su entrada.
Mi pregunta es, ¿cómo la obtengo para que el cliente pueda (usando mi programa compilado) guardar este archivo java (que extiende mi InterfaceExample) en cualquier lugar de su computadora, haga que mi programa lo compile (sin decir "no encuentro el símbolo: InterfaceExample" ) ¿luego cargarlo y llamar al método doSomething ()?
Sigo viendo Q & A''s usando reflection o ClassLoader y uno que casi describe cómo compilarlo, pero ninguno es lo suficientemente detallado para mí / no los entiendo completamente.
Eche un vistazo a JavaCompiler
Lo siguiente se basa en el ejemplo dado en los JavaDocs
Esto guardará un File
en el directorio testcompile
(basado en los requisitos del nombre del package
) y compilará el File
en una clase Java ...
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class InlineCompiler {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder(64);
sb.append("package testcompile;/n");
sb.append("public class HelloWorld implements inlinecompiler.InlineCompiler.DoStuff {/n");
sb.append(" public void doStuff() {/n");
sb.append(" System.out.println(/"Hello world/");/n");
sb.append(" }/n");
sb.append("}/n");
File helloWorldJava = new File("testcompile/HelloWorld.java");
if (helloWorldJava.getParentFile().exists() || helloWorldJava.getParentFile().mkdirs()) {
try {
Writer writer = null;
try {
writer = new FileWriter(helloWorldJava);
writer.write(sb.toString());
writer.flush();
} finally {
try {
writer.close();
} catch (Exception e) {
}
}
/** Compilation Requirements *********************************************************************************************/
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
// 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 = new ArrayList<String>();
optionList.add("-classpath");
optionList.add(System.getProperty("java.class.path") + ";dist/InlineCompiler.jar");
Iterable<? extends JavaFileObject> compilationUnit
= fileManager.getJavaFileObjectsFromFiles(Arrays.asList(helloWorldJava));
JavaCompiler.CompilationTask task = 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!
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
// Load the class from the classloader by name....
Class<?> loadedClass = classLoader.loadClass("testcompile.HelloWorld");
// Create a new instance...
Object obj = loadedClass.newInstance();
// Santity check
if (obj instanceof DoStuff) {
// Cast to the DoStuff interface
DoStuff stuffToDo = (DoStuff)obj;
// Run it baby
stuffToDo.doStuff();
}
/************************************************************************************************* Load and execute **/
} else {
for (Diagnostic<? extends JavaFileObject> 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();
}
}
}
public static interface DoStuff {
public void doStuff();
}
}
¡Ahora actualizado para incluir suplir un classpath para el compilador y cargar y ejecutar la clase compilada!