In some cases, we need to generate java code dynamically, compile dynamically, and then execute the code. JAVAAPI provides corresponding tools (JavaCompiler) to implement dynamic compilation. Below we introduce how to implement dynamic compilation of java code through JavaCompiler.
1. Get JavaCompiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
Get the java compiler provided by JDK, and if no compiler is provided, return null;
2. Compilation
//Get the java file management class StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);//Get the java file object iterator Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files);//Set the compilation parameters ArrayList<String> ops = new ArrayList<String>();ops.add("-Xlint:unchecked");//Set classpathhops.add("-classpath");ops.add(CLASS_PATH);//Get compilation task JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it);//Execute compilation task task.call();When we are referencing other code in the source code we want to compile, we need to set the reference code path to -classpath, otherwise the compilation will fail.
III. Execution
//The class name to be loaded String className = "xxx.xxx.xxx";//Get the class loader ClassLoader classLoader = XXX.class.getClassLoader();//Load the class Class<?> cls = classLoader.loadClass(className);//Calling the method name String methodName = "execute";//Method parameter type array Class<?>[] paramCls = {...};//Get the method Method method = cls.getDeclaredMethod(methodName, paramCls);//Create the class instance Object obj = cls.newInstance();//Method parameter Object[] params = {...};//Calling method Object result = method.invoke(obj, params);4. Complete code
//ClassUtil.javaimport java.io.FileWriter;import java.io.BufferedWriter;import java.io.File;import java.io.IOException;import java.util.ArrayList;import javax.tools.JavaCompiler;import javax.tools.ToolProvider;import javax.tools.JavaFileObject;import javax.tools.StandardJavaFileManager;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class ClassUtil {private static final Log logger = LogFactory.getLog(ClassUtil.class);private static JavaCompiler compiler;static{compiler = ToolProvider.getSystemJavaCompiler();}/** * Get the java file path* @param file * @return */private static String getFilePath(String file){int last1 = file.lastIndexOf('/');int last2 = file.lastIndexOf('//');return file.substring(0, last1>last2?last1:last2)+File.separatorchar;}/** * Compile java file* @param ops Compile parameters* @param files Compile file*/private static void javac(List<String> ops,String... files){StandardJavaFileManager manager = null;try{manager = compiler.getStandardFileManager(null, null, null);Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files);JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it);task.call();if(logger.isDebugEnabled()){for (String file:files) logger.debug("Compile Java File:" + file);}}catch(Exception e){logger.error(e);} finally{if(manager!=null){try {manager.close();}catch (IOException e) {e.printStackTrace();}}}}/** * Generate java file* @param file file name* @param source java code* @throws Exception */private static void writeJavaFile(String file,String source)throws Exception{if(logger.isDebugEnabled()){logger.debug("Write Java Source Code to:"+file);}BufferedWriter bw = null;try{File dir = new File(getFilePath(file));if(!dir.exists()) dir.mkdirs();bw = new BufferedWriter(new FileWriter(file));bw.write(source);bw.flush();}catch(Exception e){throw e;} finally{if(bw!=null){bw.close();}}}/** * Loading class* @param name Class name* @return */private static Class<?> load(String name){Class<?> cls = null;ClassLoader classLoader = null;try{classLoader = ClassUtil.class.getClassLoader();cls = classLoader.loadClass(name);if(logger.isDebugEnabled()){logger.debug("Load Class["+name+"] by "+classLoader);}}catch(Exception e){logger.error(e);}return cls;}/** * Compile code and load class* @param filePath java code path* @param source java code* @param clsName Class name* @param ops Compile parameters* @return */public static Class<?> loadClass(String filePath,String source,String clsName,List<String> ops){try {writeJavaFile(CLASS_PATH+filePath,source);javac(ops,CLASS_PATH+filePath);return load(clsName);}catch (Exception e) {logger.error(e);}return null;}/** * Call class method* @param cls class* @param methodName method name* @param paramsCls method parameter type* @param params method parameter* @return */public static Object invoke(Class<?> cls,String methodName,Class<?>[] paramsCls,Object[] params){Object result = null;try {Method method = cls.getDeclaredMethod(methodName, paramsCls);Object obj = cls.newInstance();result = method.invoke(obj, params);}catch (Exception e) {logger.error(e);}return result;}}V. Test
public class ClassUtilTest {private static final Log logger = LogFactory.getLog(ClassUtilTest.class);public static void main(String args[]){StringBuilder sb = new StringBuilder();sb.append("package com.even.test;");sb.append("import java.util.Map;/nimport java.text.DecimalFormat;/n");sb.append("public class Sum{/n");sb.append("private final DecimalFormat df = new DecimalFormat(/"#.#####/");/n");sb.append("public Double calculate(Map<String,Double> data){/n");sb.append("double d = (30*data.get(/"f1/") + 20*data.get(/"f2/") + 50*data.get(/"f3/"))/100;/n");sb.append("return Double.valueOf(df.format(d));}}/n");//Set the compilation parameters ArrayList<String> ops = new ArrayList<String>();ops.add("-Xlint:unchecked");//Compile the code and return classClass<?> cls = ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops);//Prepare the test data Map<String,double> data = new HashMap<String,double>();data.put("f1", 10.0);data.put("f2", 20.0);data.put("f3", 30.0);//Execute the test method Object result = ClassUtil.invoke(cls, "calculate", new Class[]{Map.class}, new Object[]{data});//Output result logger.debug(data);logger.debug("(30*f1+20*f2+50*f3)/100 = "+result);}Test results
16:12:02.860 DEBUG com.even.tools.ClassUtil - Write Java Source Code to: .../classes//com/even/test/Sum.java16:12:03.544 DEBUG com.even.tools.ClassUtil - Compile Java File:.../classes//com/even/test/Sum.java16:12:03.545 DEBUG com.even.tools.ClassUtil - Load Class[com.even.test.Sum] by sun.misc.Launcher$AppClassLoader@73d16e9316:12:03.547 DEBUG com.even.test.ClassUtilTest - {f1=10.0, f2=20.0, f3=30.0}16:12:03.547 DEBUG com.even.test.ClassUtilTest - (30*f1+20*f2+50*f3)/100 = 22.0Summarize
The above is all about Java dynamic compilation and execution code examples, I hope it will be helpful to everyone. Interested friends can continue to refer to this site:
Java programming dynamically compiled and loaded code sharing
Java Dynamic Programming Edit Distance Problem Example Code
Detailed explanation of the implementation of references and dynamic proxy in Java
If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!