How to compile and run java source code in memory -


this question has answer here:

i want treat string java file compile , run it. in other words, use java script language.

to better performance, should avoid writing .class files disk.

this answer 1 of blogs, compile , run java source code in memory.

here 3 source code files.

memoryjavacompiler.java

package me.soulmachine.compiler;  import java.io.ioexception; import java.io.printwriter; import java.io.writer; import java.lang.reflect.method; import java.util.arraylist; import java.util.list; import java.util.map;  import javax.tools.*;  /**  * simple interface java compiler using jsr 199 compiler api.  */ public class memoryjavacompiler {     private javax.tools.javacompiler tool;     private standardjavafilemanager stdmanager;      public memoryjavacompiler() {         tool = toolprovider.getsystemjavacompiler();         if (tool == null) {             throw new runtimeexception("could not java compiler. please, ensure jdk used instead of jre.");         }         stdmanager = tool.getstandardfilemanager(null, null, null);     }      /**      * compile single static method.      */     public method compilestaticmethod(final string methodname, final string classname,         final string source)         throws classnotfoundexception {         final map<string, byte[]> classbytes = compile(classname + ".java", source);         final memoryclassloader classloader = new memoryclassloader(classbytes);         final class clazz = classloader.loadclass(classname);         final method[] methods = clazz.getdeclaredmethods();         (final method method : methods) {             if (method.getname().equals(methodname)) {                 if (!method.isaccessible()) method.setaccessible(true);                 return method;             }         }         throw new nosuchmethoderror(methodname);     }       public map<string, byte[]> compile(string filename, string source) {         return compile(filename, source, new printwriter(system.err), null, null);     }       /**      * compile given string source , return bytecodes map.      *      * @param filename source filename used error messages etc.      * @param source java source string      * @param err error writer diagnostic messages written      * @param sourcepath location of additional .java source files      * @param classpath location of additional .class files      */     private map<string, byte[]> compile(string filename, string source,         writer err, string sourcepath, string classpath) {         // collect errors, warnings etc.         diagnosticcollector<javafileobject> diagnostics =             new diagnosticcollector<javafileobject>();          // create new memory javafilemanager         memoryjavafilemanager filemanager = new memoryjavafilemanager(stdmanager);          // prepare compilation unit         list<javafileobject> compunits = new arraylist<javafileobject>(1);         compunits.add(filemanager.makestringsource(filename, source));          return compile(compunits, filemanager, err, sourcepath, classpath);     }      private map<string, byte[]> compile(final list<javafileobject> compunits,          final memoryjavafilemanager filemanager,         writer err, string sourcepath, string classpath) {         // collect errors, warnings etc.         diagnosticcollector<javafileobject> diagnostics =             new diagnosticcollector<javafileobject>();          // javac options         list<string> options = new arraylist<string>();         options.add("-xlint:all");         //      options.add("-g:none");         options.add("-deprecation");         if (sourcepath != null) {             options.add("-sourcepath");             options.add(sourcepath);         }          if (classpath != null) {             options.add("-classpath");             options.add(classpath);         }          // create compilation task         javax.tools.javacompiler.compilationtask task =             tool.gettask(err, filemanager, diagnostics,                 options, null, compunits);          if (task.call() == false) {             printwriter perr = new printwriter(err);             (diagnostic diagnostic : diagnostics.getdiagnostics()) {                 perr.println(diagnostic);             }             perr.flush();             return null;         }          map<string, byte[]> classbytes = filemanager.getclassbytes();         try {             filemanager.close();         } catch (ioexception exp) {         }          return classbytes;     } } 

memoryjavafilemanager.java

package me.soulmachine.compiler;   import java.io.bytearrayoutputstream; import java.io.file; import java.io.filteroutputstream; import java.io.ioexception; import java.io.outputstream; import java.net.uri; import java.nio.charbuffer; import java.util.hashmap; import java.util.map;  import javax.tools.fileobject; import javax.tools.forwardingjavafilemanager; import javax.tools.javafilemanager; import javax.tools.javafileobject; import javax.tools.javafileobject.kind; import javax.tools.simplejavafileobject;  /**  * javafilemanager keeps compiled .class bytes in memory.  */ @suppresswarnings("unchecked") final class memoryjavafilemanager extends forwardingjavafilemanager {      /** java source file extension. */     private final static string ext = ".java";      private map<string, byte[]> classbytes;      public memoryjavafilemanager(javafilemanager filemanager) {         super(filemanager);         classbytes = new hashmap<>();     }      public map<string, byte[]> getclassbytes() {         return classbytes;     }      public void close() throws ioexception {         classbytes = null;     }      public void flush() throws ioexception {     }      /**      * file object used represent java source coming string.      */     private static class stringinputbuffer extends simplejavafileobject {         final string code;          stringinputbuffer(string filename, string code) {             super(touri(filename), kind.source);             this.code = code;         }          public charbuffer getcharcontent(boolean ignoreencodingerrors) {             return charbuffer.wrap(code);         }     }      /**      * file object stores java bytecode classbytes map.      */     private class classoutputbuffer extends simplejavafileobject {         private string name;          classoutputbuffer(string name) {             super(touri(name), kind.class);             this.name = name;         }          public outputstream openoutputstream() {             return new filteroutputstream(new bytearrayoutputstream()) {                 public void close() throws ioexception {                     out.close();                     bytearrayoutputstream bos = (bytearrayoutputstream)out;                     classbytes.put(name, bos.tobytearray());                 }             };         }     }      public javafileobject getjavafileforoutput(javafilemanager.location location,         string classname,         kind kind,         fileobject sibling) throws ioexception {         if (kind == kind.class) {             return new classoutputbuffer(classname);         } else {             return super.getjavafileforoutput(location, classname, kind, sibling);         }     }      static javafileobject makestringsource(string filename, string code) {         return new stringinputbuffer(filename, code);     }      static uri touri(string name) {         file file = new file(name);         if (file.exists()) {             return file.touri();         } else {             try {                 final stringbuilder newuri = new stringbuilder();                 newuri.append("mfm:///");                 newuri.append(name.replace('.', '/'));                 if(name.endswith(ext)) newuri.replace(newuri.length() - ext.length(), newuri.length(), ext);                 return uri.create(newuri.tostring());             } catch (exception exp) {                 return uri.create("mfm:///com/sun/script/java/java_source");             }         }     } } 

memoryclassloader.java

package me.soulmachine.compiler;   import java.io.file; import java.net.malformedurlexception; import java.net.url; import java.net.urlclassloader; import java.util.arraylist; import java.util.list; import java.util.map; import java.util.stringtokenizer;  /**  * classloader loads .class bytes memory.  */ final class memoryclassloader extends urlclassloader {     private map<string, byte[]> classbytes;      public memoryclassloader(map<string, byte[]> classbytes,         string classpath, classloader parent) {         super(tourls(classpath), parent);         this.classbytes = classbytes;     }      public memoryclassloader(map<string, byte[]> classbytes, string classpath) {         this(classbytes, classpath, classloader.getsystemclassloader());     }      public memoryclassloader(map<string, byte[]> classbytes) {         this(classbytes, null, classloader.getsystemclassloader());     }      public class load(string classname) throws classnotfoundexception {         return loadclass(classname);     }      public iterable<class> loadall() throws classnotfoundexception {         list<class> classes = new arraylist<class>(classbytes.size());         (string name : classbytes.keyset()) {             classes.add(loadclass(name));         }         return classes;     }      protected class findclass(string classname) throws classnotfoundexception {         byte[] buf = classbytes.get(classname);         if (buf != null) {             // clear bytes in map -- don't need anymore             classbytes.put(classname, null);             return defineclass(classname, buf, 0, buf.length);         } else {             return super.findclass(classname);         }     }      private static url[] tourls(string classpath) {         if (classpath == null) {             return new url[0];         }          list<url> list = new arraylist<url>();         stringtokenizer st = new stringtokenizer(classpath, file.pathseparator);         while (st.hasmoretokens()) {             string token = st.nexttoken();             file file = new file(token);             if (file.exists()) {                 try {                     list.add(file.touri().tourl());                 } catch (malformedurlexception mue) {}             } else {                 try {                     list.add(new url(token));                 } catch (malformedurlexception mue) {}             }         }         url[] res = new url[list.size()];         list.toarray(res);         return res;     } } 

explanations:

  1. in order represent java source file in memory instead of disk, defined stringinputbuffer class in memoryjavafilemanager.java.
  2. to save compiled .class files in memory, implemented class memoryjavafilemanager. main idea override function getjavafileforoutput() store bytecodes map.
  3. to load bytecodes in memory, have implement customized classloader memoryclassloader, reads bytecodes in map , turn them classes.

here unite test.

package me.soulmachine.compiler;   import org.junit.test;  import java.io.ioexception; import java.lang.reflect.invocationtargetexception; import java.lang.reflect.method; import java.util.arraylist;  import static org.junit.assert.assertequals;  public class memoryjavacompilertest {     private final static memoryjavacompiler compiler = new memoryjavacompiler();      @test public void compilestaticmethodtest()         throws classnotfoundexception, invocationtargetexception, illegalaccessexception {         final string source = "public final class solution {\n"             + "public static string greeting(string name) {\n"             + "\treturn \"hello \" + name;\n" + "}\n}\n";         final method greeting = compiler.compilestaticmethod("greeting", "solution", source);         final object result = greeting.invoke(null, "soulmachine");         assertequals("hello soulmachine", result.tostring());     } } 

reference

  1. javacompiler.java cloudera morphlines
  2. how create object string in java (how eval string)?
  3. inmemoryjavacompiler
  4. java-runtime-compiler
  5. 动态的java - 无废话javacompilerapi中文指南

Comments

Popular posts from this blog

python - pip install -U PySide error -

arrays - C++ error: a brace-enclosed initializer is not allowed here before ‘{’ token -

cytoscape.js - How to add nodes to Dagre layout with Cytoscape -