JDKには、Javaでコンパイルプロセスを開始し、Javaソースファイルを解析し、その構文ツリーを取得できる関連するコンピレーションAPIのセットがあります。このAPIの完全なセットは、JDKのjars.jarに含まれています(/library/java/javavirtualmachines/jdk_version/contents/home/libにあるOSXにあります)が、これはOracleおよびOpenJDKリリースのパブリックAPIではないため、このAPIのセットを説明する公式文書はありません。ただし、多くのプロジェクトがこのAPIを使用して多くのことを行いました。たとえば、有名なLombokはこのAPIを使用して、注釈処理段階でソースコードの構文ツリーを変更しました。最終結果は、新しいコードをソースファイルに直接挿入することと同等です!
この一連のAPIは現在関連するドキュメントがないため、使用することは困難です。たとえば、ソースコードのすべての変数を解析し、それらを印刷します。
パブリッククラスJavaparser {private static final string path = "user.java";プライベートJavacfileManager FileManager;プライベートJavactool Javactool; public javaparser(){context context = new Context(); FileManager = new JavacFileManager(Context、True、Charset.DefaultCharset()); javactool = new Javactool(); } public void parsejavafiles(){iterable <! - ? javafileobjectを拡張 - > files = filemanager.getjavafileobjects(path); javacompiler.compilationtask compilationtask = javactool.gettask(null、filemanager、null、null、null、files); javactask javactask =(javactask)compilationtask; {iterable <! - ? compilationunittreeを拡張 - > result = javactask.parse(); for(compilationunittree tree:result){tree.accept(new sourceVisitor()、null); }} catch(ioexception e){e.printstacktrace(); }} static class sourcevisitor extends treescanner <void、void = ""> {private string currentPackageName = null; @Override public void visitCompilationUnit(compilationunittree node、void nsive){return super.visitcompilationunit(node、nive); } @Override public void visitvariable(variabletree node、void asmuse){formatptrln( "variable name:%s、type:%s、deink:%s、package:%s"、node.getname()、node.getType()、node.getkind()、currentpackename); nullを返します。 }} public static void formatptrln(string format、object ... args){system.out.println(string.format(format、args)); } public static void main(string [] args){new Javaparser()。parsejavafiles(); }} </void、>user.javaのコードは次のとおりです。
パッケージcom.ragnarok.javaparser; com.sun.istack.internal.nullable; Import Java.lang.Override;パブリッククラスユーザー{@nullableプライベート文字列foo = "123123";プライベートフーA; public void usermethod(){} static class foo {private string foostring = "123123"; public void foomethod(){}}}上記のJavaparserを実行した結果は次のとおりです。
変数:foo、annotaion:nullablevariable name:foo、type:string、deink:variable、package:com.ragnarok.javaparserver変数名:a、type:foo、種類:変数、パッケージ:com.ragnarok.javaparserer
ここでは、最初にjavacompiler.compilateTaskを介してソースファイルを解析し、次にカスタムSourceVisitor(Treescannerから継承)を使用してソースコードの構造にアクセスします。 SourceVisitorクラスでは、VisitVariableをオーバーロードして、コンパイルユニット(単一のソースコードファイル)を解析し、すべての変数にアクセスします。ここでは、この変数タイプ(パッケージ名を含む)の完全な資格のある名前を取得できず、対応する単純な名前のみを取得できることがわかります。したがって、タイプの決定には、それを単独で決定するために外部実装が必要です。たとえば、クラスが配置されているパッケージ名を録画し、ソースコードディレクトリ全体を再帰的に検索して、すべてのクラスの完全に適格な名前を追跡し、インポートに対応するタイプなどが含まれているかどうかを確認できます。
VisitVariableメソッドに加えて、Treescannerには他のvisitxyzメソッドも多数含まれています。たとえば、すべてのインポート、メソッド定義、注釈などを通過できます。より具体的には、OpenJDKでこれに関するソースコードを表示できます。
ここでは、別の例を取り、VisitClassメソッドをオーバーロードして、すべての内部クラスとクラス自体にアクセスします。
@overridepublic void visitclass(clastree node、void回避){formatptrln( "class name:%s"、node.getsimplename()); for(treeメンバー:node.getMembers()){if(member instanceof variabletree){variabletree variable =(variabletree)member;リスト<! - ? AnnotationTreeを拡張 - > annotations = variable.getModifiers()。getAnnotations(); if(annotations.size()> 0){formatptrln( "variable:%s、annotaion:%s"、variable.getname()、annotations.get.getannotationType()); } else {formatptrln( "variable:%s"、variable.getname()); }}} super.visitclass(node、emsive)を返します。 }ここでは、クラス名と変数名、タイプ、および注釈タイプを印刷するだけです。上記のコードを実行すると、結果は次のとおりです。
クラス名:uservariable:foo、annotaion:nullablevariable:class name:foovariable:foostring
クラス名とクラスの変数を印刷したことがわかります。 VisitClassメソッドでは、さまざまなタイプに対応する変数、メソッド、注釈などを含むGetMembersメソッドを使用して、クラスのすべてのメンバーを取得できます。たとえば、変数はvariabletreeタイプに対応し、メソッドはメソッドツリータイプに対応します。
一般的に、実際には使用は特に複雑ではありませんが、ドキュメントが不足しているために使用する大きな障害を引き起こしています。そして、私たちが紹介しているのは、このAPIのほんの一部です。将来、このAPIの関連する機能を引き続き研究します。
上記は、Javaソースコードを解析するためのJDKのパーサーのデータの編集です。今後も関連情報を追加し続けます。このサイトへのご支援ありがとうございます!