JavaParser Snortyコードは簡単です

世界には、有名ではないが非常に便利な多くのクールで小さなライブラリがあります。 アイデアは、Habrにそのようなことをゆっくりと紹介することです。 今日はJavaParserについてお話します。







JavaParserは、Javaコードを解析、分析、変換、および生成するためのツールのコレクションです。 言い換えれば、javacodeの一部を取得し、何らかの方法で即興のメソッドで特別な知識を必要とせずに飼いならす必要がある場合、このlibaはまさにそれです。







記事の途中のどこかで、この種のものを作成できる悪夢と恐怖に突然気付くことができます。テキストを読んで怒りのコメントであふれかえるのが待ちきれません。 遠慮しないでください-一番下までスクロールしてあなたの魂を注ぐだけです:)















コードは、Apache、LGPL、およびGPLライセンスの下でgithubで配布さます。 著者は、プロジェクトのために比較的まともなサイトを作り、完全に無料で配布された小さな本をまとめました-それは、彼らの意図の深刻さを確認しています。







FOSDEMの著者に2、3の質問がありましたが、著者は賢くて適切な人々の印象を残しています。 この記事は彼らの報告に基づいています。







このライブラリは何をしますか? まず、JavaコードをAST(抽象構文ツリー)に変換します-構文解析。 第二に、彼女は既製のASTを取得し、それをJavaコードに変換することができます-解析しません。







ここでの待ち伏せとは何ですか、なぜライブラリが必要なのですか。 見て:







String habraPostText = "  , ,   "; public void writeHabraPost(String habraPostText) { habraPostText = ", .   ."; } public void writeHabraPost() { habraPostText = ", .   ."; }
      
      





これらのメソッドの両方について、ASTはJavaParserで同じものを生成します。 ASTの具象ノードは、 habraPostText



がどこhabraPostText



来たかを知りません。







または、たとえば、メソッドaMethod(int foo)



およびaMethod(String foo)



、その中にSystem.out.println



を使用して変数が出力されます。 ASTも同じになります。







したがって、JavaParserには、 symbol solver



と呼ばれる、ASTの各部分に対して、ソースの特定の対応する部分を計算するものがあります。 彼らは、GitHub上でJSSと呼ばれる別のプロジェクトの形でそれを持っています。







JavaParserがJSSなしで計算できるコードがあります。 たとえば、フィールドからゲッターを取得すると、呼び出されたフィールドへのリンクはコードに直接エンコードされます。 一方、戻り値の型を何らかの方法で巧妙に計算する方法がある場合、ここではすでに重砲、つまりJSSを接続する必要があります。 そのようなことを手動で書くのは非常に難しいでしょう。







さて、なぜこれがすべて必要なのか。 たとえば、ジャンクコード(hello、Lombok!)の生成を自動化したいとします。 または、あなたが発明したスクリプト言語のコードがJavaに変わるトランスパイラーを作成します。







これを行うコードは非常に簡単です。 habrapostaクラスを作りましょう:







 CompilationUnit cu = new CompilationUnit(); cu.setPackageDeclaration("ru.habrahabr.hub.java.examples.javaparser"); ClassOrInterfaceDeclaration habraPost = cu.addClass("HabraPost"); habraPost.addField("String", "title"); habraPost.addField("String", "text");
      
      





そして、これらのフィールドに入力することを強制するコンストラクターを追加します。







 habraPost.addConstructor(Modifier.PUBLIC) .addParameter("String", "title") .addParameter("String", "text") .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(), "text"), new NameExpr("text"), AssignExpr.Operator.ASSIGN))));
      
      





ここで、getter-setterのボイラープレートを生成します。







 habraPost.addMethod("getTitle", Modifier.PUBLIC).setBody( new BlockStmt().addStatement( new ReturnStmt(new NameExpr("title")))); habraPost.addMethod("getText", Modifier.PUBLIC).setBody( new BlockStmt().addStatement( new ReturnStmt(new NameExpr("text"))));
      
      





次に、クラスをコンソールに出力します。







 System.out.println(cu.toString());
      
      





出力は次のようになります。







 package ru.habrahabr.hub.java.examples.javaparser; public class HabraPost { String title; String text; public HabraPost(String title, String text) { this.title = title; this.text = text; } public void getTitle() { return title; } public void getText() { return text; } }
      
      





さらに、コードの調査をすぐに行うことができます。 たとえば、その品質を調査し、自動テストの形式で整理します。







 long wtfs = getNodes(myAPI, MethodDeclaration.class).stream() .filter(m -> m.getParameters().size > 10) .count(); System.out.println(String.format(" ,     : %d", wtfs));
      
      





APIによってすべてが見えるため、複雑な例にぶつかることはありません。 唯一の本当に珍しい機能は、JSSを呼び出して型を詳しく調べることができることです。 たとえば、他のクラスの最大数から(再帰的に)継承するクラスを見つけましょう。







 ResolvedReferenceTypeDeclaration c = getNodes(myAPI, ClassorInterfaceDeclaration).stream() .filter(c -> !c.isInterface()) .map(c -> c.resolve()) // JSS! .sorted(Comparator.comparingInt(o -> -1 * o.getAllAncestors().size))) .findFirst().get();
      
      





その結果、このライブラリは自動リファクタリングに使用できます。 これを行うには、IDE内で高度なリファクタリングを行うことはできませんが、JavaParserの機能のみに制限してください。 リファクタリングを行いましょう。古いメソッドの呼び出しを新しいメソッドに置き換えます。







この話を覚えていますか?















Boomburumが1日に666回脳内で実行するcheckMegamozg(Boolean moderatorInAGoodMood)



メソッドがあるとします。 checkHabrahabr(Boolean moderatorInAGoodMood)



checkHabrahabr(Boolean moderatorInAGoodMood)



する必要があります。







まず、目的の方法を探します。







 getNodes(myAPI, MethodCallExpr.class).stream() .filter(m -> m.resolveInvokedMethod()). getQialifiedSignature() .equals("ru.habrahabr.Habr.checkMegamozg(java.lang.Boolean)")) .forEach(m -> m.replace(replaceCallsToMegamozg(m)));
      
      





さて、置き換えは正確にどのようになりますか:







 public MethodCallExpr replaceCallsToMegamozg() { MethodCallExpr newMethodCall = new MethodCallExpr( methodCall.getScope.get(), "checkHabrahabr"); newMethodCall.addArgument(methodCall.getArgument(0)); return newMethodCall; }
      
      





さらに、メソッド内のどこかにコメント(hi、 lany !)があった場合、JavaParserは可能な限りあらゆる方法でコメントを失わないようにします。 これはひどく不快な作業であり、著者はこのトピックについて非常に心配しています。







ご覧のとおり、このライブラリは小さなスイス製ナイフのようなもので、シンプルで比較的信頼性があります。 将来、組み込みのテンプレート言語などの小さな機能が追加され、Javaクラスを手動ではなく、ファイルからロードして${}



を置き換えることで生成できるようになります。







すべてが好きです。 いいね、サブスクライブし、このlibについてどう思うか教えてください! さらに、別のライブラリのミニ概要を注文することもできます-最高のオファーはhabropostに変わります。







広告の分。 おそらくご存知のように、会議を行っています。 次はJBreak 2018JPoint 2018です。 そこに来て、さまざまなファッショナブルな技術の開発者とライブでチャットできます。たとえば、Azul Systemsの副CTOであるSimon Ritterがいます。 そこでは、デブリーフィングのビクターガモフや他の興味深い人々と会うことができます(そして私のようなローファーにも会えます)。 要するに、私たちはあなたを待っています。



All Articles