JavaParser生成,分析和修改Java代码
作為開發人員,我們經常鄙視手動進行重復工作的人員。
我們認為, 他們應該實現這一目標 。
盡管如此,我們還是進行與編碼有關的所有活動。 當然,我們使用的高級IDE可以為我們執行一些重構,但這基本上就是結束了。 我們不品嘗我們自己的藥。
讓我們改變它。 讓我們看看如何將代碼編寫為:
- 生成我們必須編寫的無聊的重復性Java代碼
- 分析我們的代碼以回答有關它的一些問題
- 做一些代碼處理和重構
好消息是,我們將使用一組庫來實現所有這些功能:JavaParser和它的弟弟JavaSymbolSolver。
入門
好吧,這很簡單:只需將JavaSymbolSolver添加到您的依賴項中即可。
什么是JavaSymbolSolver? 它是JavaParser的補充庫,為它提供了一些相當強大的功能,這些功能對于回答關于代碼的更復雜的問題是必需的。
JavaSymbolSolver依賴于JavaParser,因此您只需要添加JavaSymbolSolver,Maven或Gradle也會為您提供JavaParser。
我假設您知道如何使用Maven或Gradle。 如果您不喜歡,請停止閱讀并開始學習!
使用javaparser生成代碼
在某些情況下,您可能需要生成Java代碼。 例如,您可能想基于一些外部數據生成代碼,例如數據庫架構或REST API。
您可能還需要將其他語言翻譯成Java。 例如,我設計了用于生活的DSL,而當用戶只能看到我為他們構建的DSL時,我經常在后臺生成Java并將其編譯。
有時候,您只想生成樣板代碼,就像我以前在使用JavaEE和所有這些層(誰能記住編寫EJB的過程很無聊?)時使用dp一樣。
無論生成代碼的原因是什么,都可以使用JavaParser。 JavaParser不會提出問題,它只是在幫助您。
讓我們看看如何生成一個具有兩個字段的類,一個構造函數和兩個getter。 沒什么特別先進的,但是它應該使您了解使用JavaParser進行代碼生成的含義。
CompilationUnit cu = new CompilationUnit();cu.setPackageDeclaration("jpexample.model");ClassOrInterfaceDeclaration book = cu.addClass("Book"); book.addField("String", "title"); book.addField("Person", "author");book.addConstructor(Modifier.PUBLIC).addParameter("String", "title").addParameter("Person", "author").setBody(new BlockStmt().addStatement(new ExpressionStmt(new AssignExpr(new FieldAccessExpr(new ThisExpr(), "title"),new NameExpr("title"),AssignExpr.Operator.ASSIGN))).addStatement(new ExpressionStmt(new AssignExpr(new FieldAccessExpr(new ThisExpr(), "author"),new NameExpr("author"),AssignExpr.Operator.ASSIGN))));book.addMethod("getTitle", Modifier.PUBLIC).setBody(new BlockStmt().addStatement(new ReturnStmt(new NameExpr("title"))));book.addMethod("getAuthor", Modifier.PUBLIC).setBody(new BlockStmt().addStatement(new ReturnStmt(new NameExpr("author"))));System.out.println(cu.toString());最后一條指令將打印出您的代碼,并且可以立即進行編譯。 您可能希望將代碼保存到文件中而不是打印它,但是您明白了。
使用javaparser分析代碼
您可能會詢問有關代碼的許多不同問題,以及許多不同的分析方式。
首先,讓我們解析項目的所有源文件:
// Parse all source files SourceRoot sourceRoot = new SourceRoot(myProjectSourceDir.toPath()); sourceRoot.setParserConfiguration(parserConfiguration); List<ParseResult> parseResults = sourceRoot.tryToParse("");// Now get all compilation unitsList allCus = parseResults.stream() .filter(ParseResult::isSuccessful) .map(r -> r.getResult().get()) .collect(Collectors.toList());我們還創建一個方法來獲取所有編譯單元中特定類型的所有節點:
public static List getNodes(List cus, Class nodeClass) {List res = new LinkedList();cus.forEach(cu -> res.addAll(cu.findAll(nodeClass)));return res; }然后讓我們開始提問,例如:
有多少種方法采用3個以上的參數?
long n = getNodes(allCus, MethodDeclaration.class) .stream() .filter(m -> m.getParameters().size() > 3).count();System.out.println("N of methods with 3+ params: " + n);大多數方法中的三個頂級類別是什么?
getNodes(allCus, ClassOrInterfaceDeclaration.class) .stream() .filter(c -> !c.isInterface()) .sorted(Comparator.comparingInt(o -> -1 * o.getMethods().size())) .limit(3) .forEach(c -> System.out.println(c.getNameAsString() + ": " + c.getMethods().size() + " methods"));好的,您知道了。 現在去檢查您的代碼。 您沒有什么可隱藏的,對嗎?
使用javaparser轉換代碼
假設您是某個庫的滿意用戶。 幾年前,您已將其添加到依賴項中,并從此以后就愉快地使用它。 時間已經過去,您已經在整個項目中越來越多地使用它。
有一天,該有用庫的新版本出現了,您決定要更新依賴項。 現在,他們在新庫中刪除了您正在使用的方法之一。 確保已棄用它,并將其命名為oldMethod (可能告訴您一些信息……)。
現在oldMethod已被newMethod取代。 newMethod具有3個參數:前兩個參數與oldMethod相同,只是將它們取反,第三個參數是布爾值,應將其設置為true以獲得與oldMethod相同的行為。
您有對oldMethod的數百個調用…是否要一個一個地更改它們? 好吧,也許,如果您按小時收費。 或者,您可以只使用JavaParser代替。
首先,讓我們在某個文件(即JavaParser parlanse中的CompilationUnit)中找到對舊方法的所有調用:
myCompilationUnit.findAll(ethodCallExpr.class).stream().filter(m -> m.resolveInvokedMethod() .getQualifiedSignature() .equals("foo.MyClass.oldMethod(java.lang.String, int)")) .forEach(m -> m.replace(replaceCallsToOldMethod(m)));然后,讓我們將舊調用轉換為新調用:
public MethodCallExpr replaceCallsToOldMethod(MethodCallExpr methodCall) { MethodCallExpr newMethodCall = new MethodCallExpr(methodCall.getScope().get(), "newMethod"); newMethodCall.addArgument(methodCall.getArgument(1)); newMethodCall.addArgument(methodCall.getArgument(0)); newMethodCall.addArgument(new BooleanLiteralExpr(true)); return newMethodCall; }太酷了,現在我們只需要獲取修改后的CompilationUnit的代碼并將其保存到Java文件即可。
newMethod使用壽命長 !
在哪里可以找到有關javaparser的更多信息
我們還沒有看到JavaParser的眾多功能:
- JavaParser可以處理注釋,弄清楚它們所引用的元素
- JavaParser可以進行詞法保留或漂亮的打印 :您的選擇
- 它可以找出一個方法調用指向哪個方法聲明,某個類具有哪個祖先,以及更多地歸功于與JavaSymbolSolver的集成。
- 它可以將AST導出為JSON,XML,YAML,甚至可以使用Graphviz生成圖表!
您在哪里可以了解所有這些東西?
這里有一些資源:
- 我們寫了一本關于JavaParser和JavaSymbolSolver的書,可免費獲得。 它被命名為JavaParser:Visited
- Matozoid偉大的博客 :他是JavaParser的光榮維護者,這是不可阻擋的力量,每隔一個星期就會推出新版本。 誰更了解JavaParser?
- 我關于語言工程的拙劣博客 。 我是JavaSymbolSolver的維護者,我嘗試作為JavaParser中的第二命令來提供幫助。 遙遠的第二個&#55357;&#56898;
- 該項目的網站 :目前內容還不是很豐富,但是我們正在努力
- 煩惱頻道 :您有問題嗎? 在那兒問他們
摘要
幾乎沒有情況可以學習如何使用一種工具來完成三件不同的事情。 通過學習如何使用JavaParser,您可以分析,生成和修改Java代碼。
好吧,感覺就像圣誕節,不是嗎?
翻譯自: https://www.javacodegeeks.com/2017/12/javaparser-generate-analyze-modify-java-code.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的JavaParser生成,分析和修改Java代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 源源不断的近义词是什么 源源不断的近义词
- 下一篇: 阿卡接口_阿卡vs风暴