// 動態生成如下類// package yp.published.grammer;//// public class DataTesterImpl implements yp.published.grammer.DataTester {//// @Override// public boolean test(yp.published.grammer.TestData data) {// if ("a".equals(data.getCondition1())) {// if ("b".equals(data.getCondition2())) {// return true;// } else {// return false;// }// } else {// return false;// }// }// } /** * 生成一個 if ({value}.equals({paramName}.{paramMemGetterName})) { * trueStatement } else { falseStatement } 的語句 * * @param paramName * @param paramMemGetterName * @param value * @param trueStatement * @param falseStatement * @return */ private static Statement createSimpleCompareStatement(String paramName, String paramMemGetterName, String value, Statement trueStatement, Statement falseStatement) { // 生成 {paramName}.{paramMemGetterName}() 方法調用表達式 NameExpr paramExpr = new NameExpr(paramName); Expression callCondition1 = new MethodCallExpr(paramExpr, paramMemGetterName); // 生成 {value}.equals( {paramName}.{paramMemGetterName}() ) 表達式 Expression strExp = new StringLiteralExpr(value); MethodCallExpr equalCondition1 = new MethodCallExpr(strExp, "equals", Lists.newArrayList(callCondition1)); // 將truestatement falsestatement封裝為代碼塊 BlockStmt trueblock = new BlockStmt(); trueblock.setStmts(Lists.newArrayList(trueStatement)); BlockStmt falseblock = new BlockStmt(); falseblock.setStmts(Lists.newArrayList(falseStatement)); // 返回 if ({value}.equals( {paramName}.{paramMemGetterName}() ) ) { // trueblock; } else { falseblock; } 語句 return new IfStmt(equalCondition1, trueblock, falseblock); } /** * 編譯一個DataTester的子類並且執行 * * @throws Exception */ private static void testCompile() throws Exception { CompilationUnit cu = new CompilationUnit(); // 設置包名 cu.setPackage(new PackageDeclaration(ASTHelper.createNameExpr("yp.published.grammer"))); // 設置類名,DataTesterImpl,並且實現DataTester接口 ClassOrInterfaceDeclaration type = new ClassOrInterfaceDeclaration(ModifierSet.PUBLIC, false, "DataTesterImpl"); ClassOrInterfaceType interType = new ClassOrInterfaceType("yp.published.grammer.DataTester"); type.setImplements(Lists.newArrayList(interType)); ASTHelper.addTypeDeclaration(cu, type); // 在實現類裡面定義Test方法,實現了接口的Test方法 MethodDeclaration method = new MethodDeclaration(ModifierSet.PUBLIC, ASTHelper.BOOLEAN_TYPE, "test"); AnnotationExpr anno = new MarkerAnnotationExpr(ASTHelper.createNameExpr("Override")); method.setAnnotations(Lists.newArrayList(anno)); // test方法的參數TestData ReferenceType refType = ASTHelper.createReferenceType("yp.published.grammer.TestData", 0); Parameter param = ASTHelper.createParameter(refType, "data"); method.setParameters(Lists.newArrayList(param)); ASTHelper.addMember(type, method); // 定義了方法題,一個block BlockStmt block = new BlockStmt(); method.setBody(block); // 生成類似於 if ("b".equals(data.getCondition2()) { return true; } else { // return false; }的代碼 Statement stmtCon2 = createSimpleCompareStatement("data", "getCondition2", "b", new ReturnStmt(new BooleanLiteralExpr(true)), new ReturnStmt(new BooleanLiteralExpr(false))); // 生成類似的 if ("a".equals(data.getCondition1)) { stmtCon2 } else { return // false; } 的代碼 // 其中stmtCon2為上面生成的if else代碼 Statement stmt = createSimpleCompareStatement("data", "getCondition1", "a", stmtCon2, new ReturnStmt(new BooleanLiteralExpr(false))); // 設置方法體代碼塊 block.setStmts(Lists.newArrayList(stmt)); System.out.println(cu.toString()); //列印結果// package yp.published.grammer;//// public class DataTesterImpl implements yp.published.grammer.DataTester {//// @Override// public boolean test(yp.published.grammer.TestData data) {// if ("a".equals(data.getCondition1())) {// if ("b".equals(data.getCondition2())) {// return true;// } else {// return false;// }// } else {// return false;// }// }// } // 編譯上述語法樹 Boolean compileResult = CompileHelper.compileOneClassSimple(cu); if (compileResult) { // 用編譯好的類來執行測試數據 Class clazz = Class.forName("yp.published.grammer.DataTesterImpl"); TestData td1 = new TestData(); td1.setCondition1("a"); td1.setCondition2("a"); TestData td2 = new TestData(); td2.setCondition1("a"); td2.setCondition2("b"); TestData td3 = new TestData(); td3.setCondition1("b"); td3.setCondition2("a"); TestData td4 = new TestData(); td4.setCondition1("b"); td4.setCondition2("b"); DataTester tester = (DataTester) clazz.newInstance(); System.out.println("a-a test:" + tester.test(td1)); System.out.println("a-b test:" + tester.test(td2)); System.out.println("b-a test:" + tester.test(td3)); System.out.println("b-b test:" + tester.test(td4)); } }
package yp.published;import java.io.IOException;import java.net.URI;import java.util.Arrays;import javax.tools.JavaCompiler;import javax.tools.JavaFileObject;import javax.tools.SimpleJavaFileObject;import javax.tools.StandardJavaFileManager;import javax.tools.ToolProvider;import com.github.javaparser.ast.CompilationUnit;public class CompileHelper { public static Boolean compileOneClassSimple(CompilationUnit cu) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); StringObject so = new StringObject( String.format("%s.%s", cu.getPackage().getName(), cu.getTypes().get(0).getName()), cu.toString()); Iterable<String> options = Arrays.asList("-d", "target/classes"); Iterable<? extends JavaFileObject> files = Arrays.asList(so); JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, files); return task.call(); } static class StringObject extends SimpleJavaFileObject { private String contents = null; protected StringObject(String className, String contents) throws Exception { super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); this.contents = contents; } public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { return contents; } }}