package me.silentdoer.dynamicgeneration; import javax.tools.JavaCompiler; import javax.tools.SimpleJavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * if IDE is idea, change working dir to xxx/target/classes * * @author liqi.wang * @version 1.0.0 * @since 2020/9/28 15:05 */ public class Entrance { /** * package's folder must exists */ public static String inputCode = "package dynamic.generation.mock; public class UserFuck" + " { public static void test(){System.out.println("Hello444");}}"; public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException , IllegalAccessException, InstantiationException, InvocationTargetException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = compiler.getStandardFileManager(null, Locale.CHINA, StandardCharsets.UTF_8); // dynamic/generation is the based folder for generated code package File file = new File("dynamic/generation"); if (file.exists() && file.isFile()) { throw new IllegalStateException("package folder is a file"); } else if (!file.exists()) { boolean flag = file.mkdirs(); if (!flag) { throw new IllegalStateException("create package's folder failure."); } } // can cache value, and if exists .class, ignore String className = parseClassName(inputCode); StringSourceJavaObject sourceObject = new StringSourceJavaObject(className, Entrance.inputCode); List<StringSourceJavaObject> objects = Collections.singletonList(sourceObject); // define output dir List<String> options = Arrays.asList("-d", "./"); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, options, null, objects); Boolean compilerResult = task.call(); if (compilerResult) { System.out.println("compile success"); ClassLoader classLoader = Entrance.class.getClassLoader(); // this throws ClassNotFoundException Class<?> userFuck = classLoader.loadClass(className); Method test = userFuck.getMethod("test"); test.invoke(userFuck.newInstance()); } } static String parseClassName(String inputCode) { Pattern packagePattern = Pattern.compile("package\s+(\S+);\s*"); Matcher packageMatcher = packagePattern.matcher(inputCode); if (!packageMatcher.find()) { throw new IllegalArgumentException("input code is invalid."); } String packageName = packageMatcher.group(1); System.out.println("package: " + packageName); Pattern classSimpleNamePatter = Pattern.compile("public\s+class\s+(\w+)\s+\{"); Matcher classSimpleNameMatcher = classSimpleNamePatter.matcher(inputCode); if (!classSimpleNameMatcher.find()) { throw new IllegalArgumentException("input code is invalid."); } String classSimpleName = classSimpleNameMatcher.group(1); System.out.println("className: " + classSimpleName); return packageName + "." + classSimpleName; } static class StringSourceJavaObject extends SimpleJavaFileObject { private final String sourceCode; public StringSourceJavaObject(String className, String sourceCode) { // DynamicCodeGen.UserFuck . to / super(URI.create("string:///" + className.replace(".", "/") + Kind.SOURCE.extension), Kind.SOURCE); this.sourceCode = sourceCode; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return this.sourceCode; } } }