序文導入 Lombok は、Google Guava と同様に便利なツールであり、強くお勧めします。すべての Java エンジニアが使用する必要があります。 Lombok は、特に Plain Old Java Object (POJO) の Java の冗長性を開発者が排除するのに役立つ Java™ ユーティリティです。これは注釈を通じて行われます。開発環境に Lombok を実装することで、開発者は hashCode() や equals() などのメソッドの構築にかかる時間や、さまざまなアクセサーやミューテーターのカタログ化にかかる時間を大幅に節約できます。 Lombok はどのように実装されていますか? lombok.Getter をインポートします。 lombok.Setter をインポートします。 @ゲッター @セッター パブリッククラスUserInfo{ プライベート文字列ユーザーID; プライベート文字列userName; } コンパイル後に生成されたUserInfo.classファイルを開きます。 get メソッドと set メソッドが生成されていることがわかり、そこから Lombok がコンパイル時にコードを強化していることが推測できます。では、コンパイル時の強化はどのように実現されるのでしょうか? コンパイルフェーズJSR-269 提案は JDK6 で提案され、可決されました。この提案では、「プラグイン注釈プロセッサ」と呼ばれる一連の標準 API が可決されました。この API は、コンパイル時にコード内の特定の注釈を事前に処理できるため、コンパイラの動作プロセスに影響を与えます。
まとめると、Lombok の効果を実現したい場合は、JSR-269 に準拠し、コンパイル時に AST を操作するだけで済みます。もちろん、この方法で実装できるのは Lombok だけではなく、たとえば FindBug、MapStruct などもこの方法で実装されています。 成し遂げるジャンクツリーJCTree は AST 要素の基本クラスです。効果を実現するには、JCTree ノードを追加するだけで済みます。 クラス名から、どのノードが使用されているかを推測できます。一般的な説明をいくつか示します。 ツリーメーカー主に構文木ノードを生成するために使用される コードまず、アクションのスコープと期間を示すためにクラスに注釈を付ける必要があります。2 つのクラスはそれぞれ Lombok の Getter と Setter に対応します。 @Target({ElementType.TYPE}) //クラスに追加されたアノテーション @Retention(RetentionPolicy.SOURCE) //コンパイル期間に影響します public @interface Getter { } @Target({ElementType.TYPE}) //クラスに追加されたアノテーション @Retention(RetentionPolicy.SOURCE) //コンパイル期間に影響します public @interface Setter { } 新しい抽象注釈プロセッサを作成するには、AbstractProcessor を継承する必要があります。ここでは、テンプレート メソッド モードが使用されます。 パブリック抽象クラス MyAbstractProcessor は AbstractProcessor を拡張します { //構文ツリー protected JavacTrees trees; //構文ツリーノードを構築 protected TreeMaker treeMaker; //識別子 protected Names names のオブジェクトを作成します。 @オーバーライド パブリック同期されたvoid init(処理環境 processingEnv) { super.init(処理環境); this.trees = JavacTrees.instance(processingEnv); コンテキスト context = ((JavacProcessingEnvironment) processingEnv).getContext(); this.treeMaker = TreeMaker.instance(コンテキスト); this.names = Names.instance(コンテキスト); } @オーバーライド パブリックブールプロセス(Set<? extends TypeElement> アノテーション、RoundEnvironment roundEnv) { //注釈付きクラスを取得します Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(getAnnotation()); //構文ツリーを取得します。set.stream().map(element -> trees.getTree(element)).forEach(jcTree -> jcTree.accept(new TreeTranslator() { //クラス定義を取得する@Override パブリック void visitClassDef(JCTree.JCClassDecl jcClassDecl) { リスト<JCTree.JCVariableDecl> jcVariableDeclList = List.nil(); // (JCTree ツリー: jcClassDecl.defs) のすべてのメンバー変数を取得します { tree.getKind() が Tree.Kind.VARIABLE と等しい場合 JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) ツリー; jcVariableDeclList に jcVariableDeclList を追加します。 } } jcVariableDeclList.forEach(jcVariableDecl -> { jcClassDecl.defs = jcClassDecl.defs.prepend(makeMethodDecl(jcVariableDecl)); }); super.visitClassDef(jcClassDecl); } })); true を返します。 } /** * 作成メソッド * @param jcVariableDecl * @戻る */ パブリック抽象 JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl); /** * どのような注釈を取得するか * @return */ パブリック抽象クラス<? extends Annotation> getAnnotation(); } Setterアノテーション継承MyAbstractProcessorの処理に使用される @SupportedAnnotationTypes("com.ingxx.processor.Setter") //アノテーションプロセッサはどのアノテーションに対して動作します。getSupportedAnnotationTypesを書き換えることもできます。 @SupportedSourceVersion(SourceVersion.RELEASE_8) //任意のバージョンを処理でき、getSupportedSourceVersionをオーバーライドすることもできます パブリッククラス SetterProcessor は MyAbstractProcessor を拡張します { @オーバーライド パブリックJCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) { ListBuffer<JCTree.JCStatement> ステートメント = 新しい ListBuffer<>(); //関数本体を生成 this.name = name; ステートメントを追加します(treeMaker.Exec(treeMaker.Assign(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName()),treeMaker.Ident(jcVariableDecl.getName())))); JCTree.JCBlock 本体 = treeMaker.Block(0, statements.toList()); //メソッドを生成する return treeMaker.MethodDef( treeMaker.Modifiers(Flags.PUBLIC), //アクセス フラグ getNewMethodName(jcVariableDecl.getName()), //名前 treeMaker.TypeIdent(TypeTag.VOID), //戻り値の型 List.nil(), //汎用パラメータ リスト List.of(getParameters(jcVariableDecl)), //パラメータ リスト List.nil(), //例外リスト body, //メソッド本体 null //デフォルト メソッド (インターフェイスのデフォルトである可能性があります) ); } @オーバーライド パブリッククラス<? extends Annotation> getAnnotation() { Setter.class を返します。 } プライベートName getNewMethodName(Name name) { 文字列フィールド名 = name.toString(); names.fromString("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, name.length())); を返します。 } プライベートJCTree.JCVariableDecl getParameters(JCTree.JCVariableDecl prototypeJCVariable) { treeMaker.VarDef( を返す treeMaker.Modifiers(Flags.PARAMETER), // アクセス フラグ prototypeJCVariable.name, // 名前 prototypeJCVariable.vartype, // 型 null // 初期化ステートメント); } } MyAbstractProcessor から継承された Getter アノテーションを処理するために使用されます @SupportedAnnotationTypes("com.ingxx.processor.Getter") //アノテーションプロセッサはどのアノテーションに対して動作します。getSupportedAnnotationTypesを書き換えることもできます。 @SupportedSourceVersion(SourceVersion.RELEASE_8) //任意のバージョンを処理でき、getSupportedSourceVersionをオーバーライドすることもできます パブリッククラス GetterProcessor は MyAbstractProcessor を拡張します { @オーバーライド パブリックJCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) { ListBuffer<JCTree.JCStatement> ステートメント = 新しい ListBuffer<>(); //関数本体を生成します。 return this.Field name statements.append(treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName()))); JCTree.JCBlock 本体 = treeMaker.Block(0, statements.toList()); //メソッドを生成します。 return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC), getNewMethodName(jcVariableDecl.getName()), jcVariableDecl.vartype, List.nil(), List.nil(), List.nil(), body, null); } @オーバーライド パブリッククラス<? extends Annotation> getAnnotation() { Getter.class を返します。 } プライベートName getNewMethodName(Name name) { 文字列フィールド名 = name.toString(); names.fromString("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, name.length())); を返します。 } } 既存のクラスをコンパイルする javac -cp $JAVA_HOME/lib/tools.jar *.java -d 。 新しいテスト クラスを作成します。IDEA では、get set メソッドが見つからないためエラーが報告されます。無視してかまいません。 @ゲッター @セッター パブリッククラスUserInfo{ プライベート文字列ユーザーID; プライベート文字列userName; パブリック静的voidメイン(String[] args) { ユーザー情報 userInfo = 新しいユーザー情報(); ユーザー情報.setUserId("001"); userInfo.setUserName("Dewu"); System.out.println("id = "+userInfo.getUserId()+" name = "+userInfo.getUserName()); } } 次にコンパイルする //複数のプロセッサはコンマで区切られます javac -processor com.ingxx.processor.GetterProcessor,com.ingxx.processor.SetterProcessor UserInfo.java -d . コンパイルされたファイルを確認し、getメソッドとsetメソッドが生成されていることを確認します。 以上がLombokからJSR-269までの詳細です。JSリフレクションメカニズムの詳細については、123WORDPRESS.COMの他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
>>: SSH経由でリモートLinuxシステムでコマンドを実行する方法
<br />思想が東西に分かれていた時代、東洋の叡智を代表するものの一つとして「禅」は多...
多くのウェブサイトを閲覧すると、ブラウザのアドレスバーの前に小さなアイコンがあり、ブラウザのタブの位...
序文MySQLの勉強を始めたばかりで、公式サイトから最新バージョン5.7.14をダウンロードしました...
1. 依存パッケージをインストールする yum -y インストール gcc-c++ ncurses-...
シェル スクリプト言語は、すべてのプログラミング言語の中で最も単純な言語であるため、資格のある Li...
目次序文一般的な方法1. 親コンポーネントを介して子コンポーネントの発行イベントをリッスンしてpro...
データをコピーリモートでデータをコピーする場合、通常は rsync コマンドを使用しますが、小さなフ...
HTML は、World Wide Web 上で公開するために使用されるハイブリッド言語です。 XH...
一般的に言えば、コンテナが起動した後、ポート マッピングを通じてコンテナが提供するサービスを使用...
目次プロジェクトを初期化するサーバーの作成クライアントを初期化するコンポーネントの記述ファイルアップ...
ページドメインの関係:メインページ a.html はドメイン A: www.jb51.net に属し...
目次概要node.js でマルチコア CPU を最大限に活用する方法Node で子プロセスを作成する...
CSS3 では、transform 関数を使用して、テキストや画像の回転、拡大縮小、傾斜、移動という...
データベースバージョン: mysql> select version(); +--------...
序文最近、X 省のコールド チェーン トレーサビリティ システムの開発で忙しくしています。毎日午後 ...