English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
In some cases, we need to dynamically generate Java code, compile it dynamically, and then execute the code. The JAVAAPI provides the corresponding tools (JavaCompiler) to implement dynamic compilation. Below, we will introduce through a simple example how to dynamically compile Java code using JavaCompiler.
1. Get JavaCompiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
Get the Java compiler provided by JDK, if no compiler is provided, return null;
2. Compilation
//Get Java file management class StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null); //Get Java file object iterator Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files); //Set compilation parameters ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked"); //Set classpath ops.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 the source code we want to compile refers to other code, we need to set the path of the referenced code to-If not in the classpath, the compilation will fail.
3. Execution
//Class name to load String className = "xxx.xxx.xxx"; //Get class loader ClassLoader classLoader = XXX.class.getClassLoader(); //Load class Class<?> cls = classLoader.loadClass(className); //Call method name String methodName = "execute"; //Method parameter type array Class<?]>[] paramCls = {...}; //Get method Method method = cls.getDeclaredMethod(methodName , paramCls); //Create class instance Object obj = cls.newInstance(); //Method parameters Object[] params = {...}; //Invoke method Object result = method.invoke(obj, params);
IV. Complete Code
//ClassUtil.java import 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.separator character; } /** * Compile java file * @param ops Compilation parameters * @param files Compilation files */ 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(); } } } /** * Load 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 Compilation 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; } /** * Invoke class method * @param cls Class * @param methodName Method name * @param paramsCls Method parameter types * @param params Method parameters * @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; } }
Five, 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 compilation parameters ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked"); //Compile code, return class Class<?> cls = ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops); //Prepare 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 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.java 16:12:03.544 DEBUG com.even.tools.ClassUtil - Compile Java File:.../classes//com/even/test/Sum.java 16:12:03.545 DEBUG com.even.tools.ClassUtil - Load Class[com.even.test.Sum] by sun.misc.Launcher$AppClassLoader@73d16e93 16: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.0
Summary
That's all about the example of dynamic compilation and execution code of Java dynamic compilation in this article. I hope it will be helpful to everyone. Those who are interested can continue to refer to this site:
Share dynamic compilation and loading code in java programming
Example code of edit distance problem in Java dynamic programming
Detailed explanation of references and dynamic proxy implementation in Java
If there is anything lacking, please leave a message to point it out. Thank you friends for your support to this site!
Statement: The content of this article is from the network, the copyright belongs to the original author, the content is contributed and uploaded by Internet users spontaneously, this website does not own the copyright, has not been manually edited, nor does it assume relevant legal liability. If you find any suspected copyright content, please send an email to: notice#oldtoolbag.com (when sending an email, please replace # with @ to report abuse, and provide relevant evidence. Once verified, this site will immediately delete the suspected infringing content.)