importjavax.tools.*;importjava.io.*;importjava.net.URI;importjava.net.URL;importjava.net.URLClassLoader;importjava.nio.CharBuffer;importjava.util.Arrays;importjava.util.HashMap;importjava.util.Map;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/**
* Required JDK >= 1.6<br><br>
* This class can help you create the Java byte code dynamically through the string and load it into memory.<br><br>
* <p>
* HOW TO:<br>
* First step. <code>Map<String, byte[]> bytecode = DynamicLoader.compile("TestClass.java", javaSrc);</code><br>
* Second step. <code>DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(bytecode);</code><br>
* Third step. <code>Class clazz = classLoader.loadClass("TestClass");</code><br>
* <br>
* Then just like the normal use of the call this class can be.
*
* @author https://github.com/Lua12138/UtilsClass/blob/master/locals/DynamicLoader.java
*/publicclassDynamicLoader{/**
* auto fill in the java-name with code, return null if cannot find the public class
*
* @param javaSrc source code string
* @return return the Map, the KEY means ClassName, the VALUE means bytecode.
*/publicstaticMap<String,byte[]>compile(StringjavaSrc){Patternpattern=Pattern.compile("public\\s+class\\s+(\\w+)");Matchermatcher=pattern.matcher(javaSrc);if(matcher.find())returncompile(matcher.group(1)+".java",javaSrc);returnnull;}/**
* @param javaName the name of your public class,eg: <code>TestClass.java</code>
* @param javaSrc source code string
* @return return the Map, the KEY means ClassName, the VALUE means bytecode.
*/publicstaticMap<String,byte[]>compile(StringjavaName,StringjavaSrc){JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();StandardJavaFileManagerstdManager=compiler.getStandardFileManager(null,null,null);try(MemoryJavaFileManagermanager=newMemoryJavaFileManager(stdManager)){JavaFileObjectjavaFileObject=manager.makeStringSource(javaName,javaSrc);JavaCompiler.CompilationTasktask=compiler.getTask(null,manager,null,null,null,Arrays.asList(javaFileObject));if(task.call())returnmanager.getClassBytes();}catch(IOExceptione){e.printStackTrace();}returnnull;}publicstaticclassMemoryClassLoaderextendsURLClassLoader{Map<String,byte[]>classBytes=newHashMap<String,byte[]>();publicMemoryClassLoader(Map<String,byte[]>classBytes){super(newURL[0],MemoryClassLoader.class.getClassLoader());this.classBytes.putAll(classBytes);}publicvoidsetClassBytes(Map<String,byte[]>classBytes){this.classBytes=classBytes;}@OverrideprotectedClass<?>findClass(Stringname)throwsClassNotFoundException{byte[]buf=classBytes.get(name);if(buf==null){returnsuper.findClass(name);}classBytes.remove(name);returndefineClass(name,buf,0,buf.length);}}}/**
* JavaFileManager that keeps compiled .class bytes in memory.
*/@SuppressWarnings("unchecked")finalclassMemoryJavaFileManagerextendsForwardingJavaFileManager{/**
* Java source file extension.
*/privatefinalstaticStringEXT=".java";privateMap<String,byte[]>classBytes;publicMemoryJavaFileManager(JavaFileManagerfileManager){super(fileManager);classBytes=newHashMap<String,byte[]>();}publicMap<String,byte[]>getClassBytes(){returnclassBytes;}publicvoidclose()throwsIOException{classBytes=newHashMap<String,byte[]>();}publicvoidflush()throwsIOException{}/**
* A file object used to represent Java source coming from a string.
*/privatestaticclassStringInputBufferextendsSimpleJavaFileObject{finalStringcode;StringInputBuffer(Stringname,Stringcode){super(toURI(name),Kind.SOURCE);this.code=code;}publicCharBuffergetCharContent(booleanignoreEncodingErrors){returnCharBuffer.wrap(code);}publicReaderopenReader(){returnnewStringReader(code);}}/**
* A file object that stores Java bytecode into the classBytes map.
*/privateclassClassOutputBufferextendsSimpleJavaFileObject{privateStringname;ClassOutputBuffer(Stringname){super(toURI(name),Kind.CLASS);this.name=name;}publicOutputStreamopenOutputStream(){returnnewFilterOutputStream(newByteArrayOutputStream()){publicvoidclose()throwsIOException{out.close();ByteArrayOutputStreambos=(ByteArrayOutputStream)out;classBytes.put(name,bos.toByteArray());}};}}publicJavaFileObjectgetJavaFileForOutput(Locationlocation,StringclassName,JavaFileObject.Kindkind,FileObjectsibling)throwsIOException{if(kind==JavaFileObject.Kind.CLASS){returnnewClassOutputBuffer(className);}else{returnsuper.getJavaFileForOutput(location,className,kind,sibling);}}staticJavaFileObjectmakeStringSource(Stringname,Stringcode){returnnewStringInputBuffer(name,code);}staticURItoURI(Stringname){Filefile=newFile(name);if(file.exists()){returnfile.toURI();}else{try{finalStringBuildernewUri=newStringBuilder();newUri.append("mfm:///");newUri.append(name.replace('.','/'));if(name.endsWith(EXT))newUri.replace(newUri.length()-EXT.length(),newUri.length(),EXT);returnURI.create(newUri.toString());}catch(Exceptionexp){returnURI.create("mfm:///com/sun/script/java/java_source");}}}}
@Testvoidtest()throwsException{StringclassContent="public class TestInterface {\n"+" public void sayHello() {\n"+" System.out.println(\"halo wode\");\n"+" }\n"+"\n"+" public int returnAdd(int a, int b) {\n"+" return a + b;\n"+" }\n"+"}";System.out.println("更换字节码:\n"+classContent);Map<String,byte[]>bytecode=DynamicLoader.compile(classContent);DynamicLoader.MemoryClassLoaderclassLoader=newDynamicLoader.MemoryClassLoader(bytecode);Class<?>clazz=classLoader.loadClass("TestInterface");Objecto=clazz.newInstance();Methodmethod=clazz.getMethod("sayHello");method.invoke(o);System.out.println("------------------------------");classContent="public class TestInterface {\n"+" public void sayHello() {\n"+" System.out.println(\"Hello World\");\n"+" }\n"+"\n"+" public int returnAdd(int a, int b) {\n"+" return a + b;\n"+" }\n"+"}";System.out.println("更换字节码:\n"+classContent);bytecode=DynamicLoader.compile(classContent);classLoader=newDynamicLoader.MemoryClassLoader(bytecode);Class<?>aClazz=classLoader.loadClass("TestInterface");Objecto1=aClazz.newInstance();MethodsayHello=aClazz.getMethod("sayHello");sayHello.invoke(o1);}