[Java] 32. Reflection機能を使う方法(Annotation編)
こんにちは。明月です。
この投稿はJavaのReflection機能を使う方法(Annotation編)に関する説明です。
以前の投稿でJavaのReflection機能をClassとMethod、Variableを分けて説明しました。
link - [Java] 29. Reflection機能を使う方法(Class編)
link - [Java] 30. Reflection機能を使う方法(Method編)
link - [Java] 31. Reflection機能を使う方法(Variable編)
今まではReflectionがクラスを割り当てするか内部関数、変数の値を取得することで使いました。
JavaではAnnotationは機能が何もないです。AnnotationはJavaでメタデータの役だけです。つまり、Javaのコードの解析記述や説明に関数データです。
でも、AnnotationはJavaのReflectionと一緒で使えば単純なメタデータの機能だけではないです。
Copy! [Source view] Example.javaimport java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; // アノテーション生成(クラス用) // RUNTIME設定してないと実行する時にgetDeclaredAnnotationsで探索ができない。 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TestAnnotation { // 基本default値 public String value() default ""; } // アノテーション設定 @TestAnnotation("Hello world") class Example { // 実行関数 public static void main(String[] args) { // Exampleでアノテーション Annotation[] annos = Example.class.getAnnotations(); // すべてアノテーション出力 for (Annotation anno : annos) { // コンソール出力 System.out.println(anno.toString()); // TestAnnotationアノテーションなら if (anno.annotationType() == TestAnnotation.class) { TestAnnotation a = (TestAnnotation) anno; // TestAnnotationのvalueの値を出力 System.out.println(a.value()); } } } }
上の例をみれば、Exampleでアノテーションの値を取得して設定されているvalueの値をコンソール出力に出力しました。
ここまでみればアノテーションのReflectionは別に活用度がなさそうです。
Copy! [Source view] Example.javaimport java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; // アノテーション生成(メンバー変数用) // RUNTIME設定しなければ実行する時、getDeclaredAnnotationsで探索ができない。 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface DependancyInjection { // 自動生成されるクラスタイプ。基本タイプはObject public Class<?> value() default Object.class; } // クラス class Node { // コンストラクタ public Node() { } // 関数生成 public void print() { // コンソール出力 System.out.println("Hello world"); } } // 親クラス class Abstract { // コンストラクタ public Abstract() { try { // メンバー変数を取得 for (Field field : Example.class.getDeclaredFields()) { // DependancyInjectionアノテーション取得 DependancyInjection anno = field.getDeclaredAnnotation(DependancyInjection.class); // あれば? if (anno != null) { // アクセス修飾子を無視 field.setAccessible(true); // value関数値を取得 Class<?> clz = anno.value(); Constructor<?> constructor; // もしかしてObjectタイプなら if (clz == Object.class) { // メンバー変数のタイプを取得する。 clz = field.getType(); } // インスタンス生成 constructor = clz.getConstructor(); // 値を格納 field.set(this, constructor.newInstance()); } } } catch (Throwable e) { e.printStackTrace(); } } } // 親クラスを継承する。 class Example extends Abstract { // 依存性注入のアノテーションがあるメンバー変数 @DependancyInjection() private Node node1; // 依存性注入のアノテーションがないメンバー変数 private Node node2; // 出力関数 public void print() { // node1がnullではなければ if (this.node1 != null) { // print関数を呼び出す。 this.node1.print(); } else { // コンソール出力 System.out.println("node1 null"); } // node2がnullではなければ if (this.node2 != null) { // print関数を呼び出す。 this.node2.print(); } else { // コンソール出力 System.out.println("node2 null"); } } // 実行関数 public static void main(String[] args) { // Exampleインスタンス生成 Example ex = new Example(); // 関数呼び出す。 ex.print(); } }
上のソースをみればExampleクラスでメンバー変数を二つを宣言します。そして親抽象クラスのコンストラクタからDependancyInjectionのアノテーションを持っている変数に変数に関してインスタンス生成します。
結果でprint関数を呼び出すとnode1はnullではなく、print関数が呼び出せることを確認できます。
Copy! [Source view] Example.javaimport java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; // アノテーション生成(メンバー変数用) // RUNTIME設定しなければ実行する時、getDeclaredAnnotationsで探索ができない。 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface AutoExecute { public int value() default 0; } // 親クラス class Abstract { // コンストラクタ public Abstract() { try { // 関数を取得 for (Method method : Example.class.getDeclaredMethods()) { // AutoExecuteのアノテーション取得 AutoExecute anno = method.getDeclaredAnnotation(AutoExecute.class); // あれば? if (anno != null) { // アクセス修飾子を無視 method.setAccessible(true); // 関数を実行 method.invoke(this); } } } catch (Throwable e) { // エラーをコンソール出力 e.printStackTrace(); } } } // 親クラスを継承する。 class Example extends Abstract { // 自動実行するアノテーション設定 @AutoExecute // 関数設定 public void print() { // コンソール出力 System.out.println("print"); } // 自動実行するアノテーション設定 @AutoExecute // 関数設定 public void run() { // コンソール出力 System.out.println("run"); } // 自動実行するアノテーション設定 @AutoExecute // 関数設定 public void test() { // コンソール出力 System.out.println("test"); } // 関数設定 public void close() { // コンソール出力 System.out.println("close"); } // 実行関数 public static void main(String[] args) { new Example(); } }
上の関数はコンストラクタからAutoExecuteアノテーションを持っている関数を探して実行する関数です。
print関数とrun、testはアノテーションが設定されているので実行されることを確認できます。
元にアノテーションはメタデータの機能だけありますが、Reflectionと一緒に使えば依存性注入や実行パターンを設定する(戦略パターン、Facadeパターン)などの様々なパターンを設定することができます。
ここまでJavaのReflection機能を使う方法(Annotation編)に関する説明でした。
ご不明なところや間違いところがあればコメントしてください。
- [Java] 39. Spring Web Frameworkを利用してウェブサービスプロジェクトを作成する方法2019/10/02 21:00:22
- [Java] 38. Javaでウェブサービスプロジェクト(JSP Servlet)を作成する方法2019/10/01 21:48:08
- [Java] 37.イクリプス(eclipse)でトムキャット(tomcat)を設定する方法2019/09/30 22:19:34
- [Java] 36.コーディングする時、よく使うコーディングパターンとステップ数を減らす方法2019/09/27 20:39:09
- [Java] 35. コーディング規約設定(Google Standard coding style)2019/09/26 21:31:25
- [Java] 34. WindowでMariaDBをインストールする方法2019/09/25 19:58:30
- [Java] 33. オープンライブラリを参照する方法(eclipseからmavenを連結)2019/09/24 19:35:54
- [Java] 32. Reflection機能を使う方法(Annotation編)2019/09/24 00:19:25
- [Java] 31. Reflection機能を使う方法(Variable編)2019/09/20 22:34:40
- [Java] 30. Reflection機能を使う方法(Method編)2019/09/19 20:20:10
- [Java] 29. Reflection機能を使う方法(Class編)2019/09/18 20:02:14
- [Java] 28. 文字タイプ(CharacterSet)とエンディアン(endian)で変換する方法2019/09/17 20:22:02
- [Java] 27. ネットワーク通信(Socket)をする方法2019/09/16 23:42:46
- [Java] 26. ファイル(IO)を扱う方法(ファイル作成、ファイル修正、アクセス日付変更とIOをclose(リソース返却)する理由、Closableインタフェース)2019/09/13 20:03:58
- [Java] 25. Objectクラス(notify、waitの使い方)2019/09/13 00:58:31
- check2024/04/10 19:03:53
- [Java] 64.Spring bootとReactを連結する方法(Buildする方法)2022/03/25 21:02:18
- [Javascript] Node.jsをインストールしてReactを使う方法2022/03/23 18:01:34
- [Java] 63. Spring bootでcronスケジューラとComponentアノテーション2022/03/16 18:57:30
- [Java] 62. Spring bootでWeb-Filterを設定する方法(Spring Security)2022/03/15 22:16:37
- [Java] JWT(Json Web Token)を発行、確認する方法2022/03/14 19:12:58
- [Java] 61. Spring bootでRedisデータベースを利用してセッションクラスタリング設定する方法2022/03/01 18:20:52
- [Java] 60. Spring bootでApacheの連結とロードバランシングを設定する方法2022/02/28 18:45:48
- [Java] 59. Spring bootのJPAでEntityManagerを使い方2022/02/25 18:27:48
- [Java] 58. EclipseでSpring bootのJPAを設定する方法2022/02/23 18:11:10
- [Java] 57. EclipseでSpring bootを設定する方法2022/02/22 19:04:49
- [Python] Redisデータベースに接続して使い方2022/02/21 18:23:49
- [Java] Redisデータベースを接続して使い方(Jedisライブラリ)2022/02/16 18:13:17
- [C#] Redisのデータベースを接続して使い方2022/02/15 18:46:09
- [CentOS] Redisデータベースをインストールする方法とコマンドを使い方2022/02/14 18:33:07