
spinal.sim.DynamicCompiler Maven / Gradle / Ivy
package spinal.sim;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Locale;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
/**
* Dynamic java class compiler and executer
* Demonstrate how to compile dynamic java source code,
* instantiate instance of the class, and finally call method of the class
*
* http://www.beyondlinux.com
*
* @author david 2011/07
*/
public class DynamicCompiler {
/**
* where shall the compiled class be saved to (should exist already)
*/
// private static String classOutputFolder = "/tmp";
public static class MyDiagnosticListener implements DiagnosticListener {
public void report(Diagnostic extends JavaFileObject> diagnostic) {
System.out.println("Line Number->" + diagnostic.getLineNumber());
System.out.println("code->" + diagnostic.getCode());
System.out.println("Message->"
+ diagnostic.getMessage(Locale.ENGLISH));
System.out.println("Source->" + diagnostic.getSource());
System.out.println(" ");
}
}
/**
* java File Object represents an in-memory java source file
* so there is no need to put the source file on hard disk
**/
public static class InMemoryJavaFileObject extends SimpleJavaFileObject {
private String contents = null;
public InMemoryJavaFileObject(String className, String contents) throws Exception {
super(URI.create("string:///" + className.replace('.', '/')
+ Kind.SOURCE.extension), Kind.SOURCE);
this.contents = contents;
}
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException {
return contents;
}
}
/**
* Get a simple Java File Object ,
* It is just for demo, content of the source code is dynamic in real use case
*/
private static JavaFileObject getJavaFileObject() {
StringBuilder contents = new StringBuilder(
"package math;" +
"public class Calculator { "
+ " public void testAdd() { "
+ " System.out.println(200+300); "
+ " } "
+ " public static void main(String[] args) { "
+ " Calculator cal = new Calculator(); "
+ " cal.testAdd(); "
+ " } " + "} ");
JavaFileObject so = null;
try {
so = new InMemoryJavaFileObject("math.Calculator", contents.toString());
} catch (Exception exception) {
exception.printStackTrace();
}
return so;
}
/**
* compile your files by JavaCompiler
*/
public static void compile(Iterable files, String classOutputFolder) {
//get system compiler:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// for compilation diagnostic message processing on compilation WARNING/ERROR
MyDiagnosticListener c = new MyDiagnosticListener();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(c,
Locale.ENGLISH,
null);
//specify classes output folder
// System.out.println("********** " + System.getProperty("java.class.path"));
String separator = System.getProperty("path.separator");
String myPath = DynamicCompiler.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String classpath = System.getProperty("java.class.path") + separator + myPath;
Iterable options = Arrays.asList("-d", classOutputFolder, "-classpath", classpath);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager,
c, options, null,
files);
Boolean result = task.call();
}
/**
* run class from the compiled byte code file by URLClassloader
*/
public static void runIt(String classOutputFolder) {
// Create a File object on the root of the directory
// containing the class file
File file = new File(classOutputFolder);
try {
// Convert File to a URL
URL url = file.toURI().toURL(); // file:/classes/demo
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
ClassLoader loader = new URLClassLoader(urls);
// Load in the class; Class.childclass should be located in
// the directory file:/class/demo/
Class thisClass = loader.loadClass("math.Calculator");
Class params[] = {};
Object paramsObj[] = {};
Object instance = thisClass.newInstance();
Method thisMethod = thisClass.getDeclaredMethod("testAdd", params);
// run the testAdd() method on the instance:
thisMethod.invoke(instance, paramsObj);
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Class getClass(String className, String classOutputFolder) {
// Create a File object on the root of the directory
// containing the class file
File file = new File(classOutputFolder);
try {
// Convert File to a URL
URL url = file.toURI().toURL(); // file:/classes/demo
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
ClassLoader loader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
// Load in the class; Class.childclass should be located in
// the directory file:/class/demo/
Class thisClass = loader.loadClass(className);
// Class params[] = {};
// Object paramsObj[] = {};
// Object instance = thisClass.newInstance();
return thisClass;
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
//1.Construct an in-memory java source file from your dynamic code
JavaFileObject file = getJavaFileObject();
Iterable files = Arrays.asList(file);
//2.Compile your files by JavaCompiler
compile(files, "/tmp");
//3.Load your class by URLClassLoader, then instantiate the instance, and call method by reflection
runIt("/tmp");
}
}