JAvaメモリ動的コンパイル
5380 ワード
public class MemoryCompiler {
private static MemoryCompiler compiler = new MemoryCompiler();
private MemoryCompiler(){
}
public static MemoryCompiler getInstance(){
return compiler;
}
public static void main(String[] args) throws Throwable{
StringBuilder source = new StringBuilder();
source.append("public class MemoryClass {
");
source.append(" public boolean m(String v) {
");
source.append(" return \"e2say\".equals(v);
");
source.append(" }
");
source.append(" public int m(int v) {
");
source.append(" return v*((v+1)-2*3/4);
");
source.append(" }
");
source.append("}");
System.out.println(source);
/*1、 */
Class<?> cls = getInstance().compile("MemoryClass", source.toString());
/*2、 */
Object obj = cls.newInstance();
/*3、 */
Object rtn1 = cls.getMethod("m", String.class).invoke(obj, "e2say");
System.out.println("m(\"e2say\"):"+rtn1);
Object rtn2 = cls.getMethod("m", int.class).invoke(obj, 10);
System.out.println("m(10):"+rtn2);
}
public Class<?> compile(String className, String content) throws Throwable{
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnostics, null, null));
URLClassLoader classLoader = (URLClassLoader) JinGuo.class.getClassLoader();
StringBuilder classPath = new StringBuilder();
for(URL url:classLoader.getURLs()){
classPath.append(url.getFile()).append(File.pathSeparator);
}
//System.out.println(classPath);
JavaCompiler.CompilationTask task = compiler.getTask(null,
fileManager,
diagnostics,
Arrays.asList("-encoding", "UTF-8", "-classpath", classPath.toString()),
null,
Arrays.asList(new JavaSourceObject(className, content)));
if(task.call()){
MemoryClassLoader loader = new MemoryClassLoader(classLoader);
JavaClassObject classObject = fileManager.getJavaClassObject(className);
Class<?> cls = loader.loadClass(className, classObject);
return cls;
}else{
for(Diagnostic<? extends JavaFileObject> diagnostic:diagnostics.getDiagnostics()){
StringBuffer buf = new StringBuffer();
buf.append("Code:" + diagnostic.getCode() + "
");
buf.append("Kind:" + diagnostic.getKind() + "
");
buf.append("Position:" + diagnostic.getPosition() + "
");
buf.append("Start Position:" + diagnostic.getStartPosition() + "
");
buf.append("End Position:" + diagnostic.getEndPosition() + "
");
buf.append("Source:" + diagnostic.getSource() + "
");
buf.append("Message:" + diagnostic.getMessage(null) + "
");
buf.append("LineNumber:" + diagnostic.getLineNumber() + "
");
buf.append("ColumnNumber:" + diagnostic.getColumnNumber() + "
");
System.out.println(buf.toString());
}
}
return null;
}
/** */
private class JavaSourceObject extends SimpleJavaFileObject {
private CharSequence content;
public JavaSourceObject(String className, CharSequence content) {
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return content;
}
}
/** class JavaClassObject ByteArrayOutputStream*/
private class ClassFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
public ClassFileManager(StandardJavaFileManager standardManager) {
super(standardManager);
}
private HashMap<String,JavaClassObject> classMap = new HashMap<String,JavaClassObject>();
public JavaClassObject getJavaClassObject(String className) {
return classMap.get(className);
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String className,
JavaFileObject.Kind kind, FileObject sibling) throws IOException {
JavaClassObject classObject = new JavaClassObject(className, kind);
classMap.put(className, classObject);
return classObject;
}
}
private class JavaClassObject extends SimpleJavaFileObject {
protected final ByteArrayOutputStream bos = new ByteArrayOutputStream();
public JavaClassObject(String name, Kind kind) {
super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind);
}
public byte[] getBytes() {
return bos.toByteArray();
}
@Override
public OutputStream openOutputStream() throws IOException {
return bos;
}
}
/** */
private class MemoryClassLoader extends URLClassLoader {
public MemoryClassLoader(ClassLoader parent) {
super(new URL[0], parent);
}
public Class<?> loadClass(String className, JavaClassObject classObject) {
byte[] bytes = classObject.getBytes();
//defineClass protected
return defineClass(className, bytes, 0, bytes.length);
}
}
}