用語法樹動態生成java代碼(生成接口實現類)例子

2020-12-13 開源中國

// 動態生成如下類// 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; } }}

相關焦點

  • 動態代理最全詳解系列[2]-Proxy生成代理類對象源碼分析
    之前我們通過JDK中的Proxy實現了動態代理,Proxy用起來是比較簡便的,但理解起來不是那麼清晰,是因為我們並沒有看見代理類是怎麼生成的,代理類怎麼調用的被代理類方法,所以下面我們進入源碼看一下。
  • smart-doc 2.0.2 發布,Java 零註解 API 文檔生成工具
    smart-doc 是一款同時支持 java restful api 和 Apache Dubbo rpc 接口文檔生成的工具,smart-doc 顛覆了傳統類似 swagger 這種大量採用註解侵入來生成文檔的實現方法
  • smart-doc 1.9.6 發布,Java 零註解 API 文檔生成工具
    ,smart-doc顛覆了傳統類似swagger這種大量採用註解侵入來生成文檔的實現方法。smart-doc完全基於接口源碼分析來生成接口文檔,完全做到零註解侵入,你只需要按照java標準注釋編寫,smart-doc就能幫你生成一個簡易明了的markdown 或是一個像GitBook樣式的靜態html文檔。如果你已經厭倦了swagger等文檔工具的無數註解和強侵入汙染,那請擁抱smart-doc吧!
  • 問:JDK 動態代理調用接口方法時是怎麼做到先調用 invoke 方法的?
    尋找真相JDK 動態代理的代理類是運行時通過字節碼生成的,我們通過Proxy.newProxyInstance方法獲取的接口實現類就是這個字節碼生成的代理類,所以要想搞明白問題本質就得從這個生成的類下手,即怎麼獲得這個運行時生成類的字節碼文件。
  • SAP ABAP關鍵字語法圖和ABAP代碼自動生成工具Code Composer
    使用ABAP的字符串模板,我們同樣可以實現類似Java Velocity動態生成代碼的需求。Jerry之前的文章 淺談Java和SAP ABAP的靜態代理和動態代理,以及ABAP面向切面編程的嘗試 曾經介紹過。將需要動態創建的ABAP類的原始碼用字符串模板拼湊好,存儲到內表lt_source中,然後調用關鍵字GENERATE SUBROUTINE POOL,創建生命周期只存在於當前會話期間內的臨時ABAP類。
  • Java 如何實現動態腳本?
    本文分享了一種 Java 動態腳本實現方案,給出了其中的關鍵技術點,並就類重名問題、生命周期、安全問題等做出進一步討論,歡迎同學們共同交流。文末福利:Java 學習路線。繁星是一個數據服務平臺,其核心功能是:用戶配置一段 SQL,繁星產出對應的 HSF/TR/SOA/Http 取數接口。一次查詢請求經過引擎的管道,被各個閥門處理後就得到了相應的結果數據。
  • 跟我學java編程—Set接口實現類TreeSet
    待加入的元素如何實現compareTo方法呢?Java提供了一個Comparable接口,該接口定義了一個compareTo(Object o)方法,用於比較兩個元素的大小,並返回一個整數值。需要加入TreeSet集合的元素必須要實現該接口,該接口的實現代碼用於比較當前元素與傳入元素的大小進行比較,並返回結果。因此實現該接口類的對象就可以比較大小。
  • Java程式設計師開發必備 MyBatis高級應用之逆向工程自動生成SQL語句
    MyBatis的一個主要的特點就是需要程式設計師自己編寫sql,那麼如果表太多的話,難免會很麻煩,所以mybatis官方提供了一個逆向工程,可以針對單表自動生成mybatis執行所需要的代碼,一般在開發中,常用的逆向工程方式是通過資料庫的表生成代碼。
  • smart-doc 1.8.1 發布,Java 零註解文檔生成工具
    smart-doc是一個java restful api文檔生成工具, smart-doc完全基於接口源碼分析來生成接口文檔,完全做到零註解侵入
  • smart-doc 1.9.4 發布,Java 零註解 API 文檔生成工具
    ,smart-doc顛覆了傳統類似swagger這種大量採用註解侵入來生成文檔的實現方法。smart-doc完全基於接口源碼分析來生成接口文檔,完全做到零註解侵入,你只需要按照java標準注釋編寫,smart-doc就能幫你生成一個簡易明了的markdown 或是一個像GitBook樣式的靜態html文檔。如果你已經厭倦了swagger等文檔工具的無數註解和強侵入汙染,那請擁抱smart-doc吧!
  • smart-doc 2.0.1 發布,Java 零註解 API 文檔生成工具
    ,smart-doc顛覆了傳統類似swagger這種大量採用註解侵入來生成文檔的實現方法。smart-doc完全基於接口源碼分析來生成接口文檔,完全做到零註解侵入,你只需要按照java標準注釋編寫,smart-doc就能幫你生成一個簡易明了的markdown 或是一個像GitBook樣式的靜態html文檔。如果你已經厭倦了swagger等文檔工具的無數註解和強侵入汙染,那請擁抱smart-doc吧!
  • smart-doc 1.9.9 發布,Java 零註解 API 文檔生成工具
    ,smart-doc顛覆了傳統類似swagger這種大量採用註解侵入來生成文檔的實現方法。smart-doc完全基於接口源碼分析來生成接口文檔,完全做到零註解侵入,你只需要按照java標準注釋編寫,smart-doc就能幫你生成一個簡易明了的markdown 或是一個像GitBook樣式的靜態html文檔。如果你已經厭倦了swagger等文檔工具的無數註解和強侵入汙染,那請擁抱smart-doc吧!
  • Java 第一大框架:Spring 的 IoC 跟 AOP 雛形如何實現?
    可是這些又需要我們創建另一些工廠類、生成器類,我們又要而外管理這些類,增加了我們的負擔。所以用另外的方式,如果對象需要的時候,就自動地生成對象,不用再去創建。舉個例子:原來我們餓了,就出去吃飯,但是現在有了外賣之後,就可以訂餐了,我們可以把我們的需求告訴美團,讓他們給我們送飯。這裡主導關係發生了變化,原來是我們自己,但是現在是美團。
  • smart-doc 2.0.0 重磅發布,Java 零註解 API 文檔生成工具
    ,smart-doc顛覆了傳統類似swagger這種大量採用註解侵入來生成文檔的實現方法。smart-doc完全基於接口源碼分析來生成接口文檔,完全做到零註解侵入,你只需要按照java標準注釋編寫,smart-doc就能幫你生成一個簡易明了的markdown 或是一個像GitBook樣式的靜態html文檔。如果你已經厭倦了swagger等文檔工具的無數註解和強侵入汙染,那請擁抱smart-doc吧!
  • Spring Boot Swagger2自動生成接口文檔和Mock模擬數據
    1.1 Swagger介紹Swagger是全球最流行的接口文檔自動生成和測試的框架,幾乎支持所有的開發語言。Easy Mock能一鍵導入Swagger所有接口,省去了手動錄製接口的麻煩,而且能夠完美的適配Swagger中的代碼注釋,可謂開發利器。Easy Mock數據是保存在雲端的,而且可以創建團隊項目,可以真正的實現前端脫離後端進行項目開發。
  • 簡要解析:Java中隨機數生成的代碼實現
    double rand = Math.random();        通過Random類的對象  程序可生成許多不同類型的隨機數字,做法很簡單,只需調用方法nextInt()和nextFloat()即可(也可以調用nextLong()或者nextDouble())。
  • java 小工具 | 封裝通用的 Mybatis 生成模板 |1 秒寫完增刪改查
    /2019/07/23/1563857782748.html今天小刀和各位小夥伴們一起來深入下這個問題,我們來研究下怎麼去封裝一個通用的Mybatis模板,讓簡單的增刪改查操作,直接通過我們的代碼生成工具就能解決,讓工具從demo級別上升到生產可用的項目mybatis簡單介紹相信很多小夥伴都已經用過Mybatis了,很簡單方便, 在springboot的集成環境裡面,寫個DAO
  • Java接口interface、抽象類abstract,逐步學習怎麼封裝對象
    Java基礎之多態,動態綁定多態的代碼案例,簡單卻很重要)中說到了繼承和多態,這裡不得不提一下java>抽象方法只能存在於抽象類或接口中,但抽象類卻能存在非抽象方法,即接口是百分之百的抽象類。以下的一個java接口的例子是類實現了Comparatble接口,這個接口代表了具有進行比較的能力,任何類實現了Comparable接口,這個類就具有了比較對象的能力,也就能進行排序操作。
  • Dodo Framework v1.1.0 發布,基於代碼生成引擎的 Java Web 自動化...
    一句話概括這個項目:這是一個基於代碼生成引擎的Java Web系統自動化開發框架。簡單的說,就是一個Java Web整合的基礎框架加上一個代碼生成引擎。學習成本極低(幾個註解,僅應用在Java 實體類),大眾化的基礎框架(SpringMVC、Hibernate、Freemarker),瞬間生成完全手寫代碼,代碼注釋完備,安全健壯,命名規範,可讀性高,可維護,可擴展,針對特定需求可輕鬆修改。
  • java——Scnner()類下面有幾種方法呢?
    一、Scnner類 Scnner類在java.util包中一個可以使用正則表達式來解析基本類型和字符串的簡單文本掃描器 例如,以下代碼使用戶能夠從 System.in 中讀取一個數: 再看一個例子,以下代碼使 long 類型可以通過 myNumbers 文件中的項分配: 掃描器還可以使用不同於空白的分隔符。