紀錄了 Java 的 Annotation (標註、註解) 自製範例。
範例的需求為:
-
自定一個 Annotation,名為 CustomAnnotation,其可添加在一個簽名為 public
String xxx(String somtText) 的 method 上,例如:
@CustomAnnotation(info="someInfo") public printSomthing(String info){ ////////////// }
-
我們模擬一個可能的框架,其中希望找出有被標上 CustomAnnotation 的 method,讀出 CustomAnnotation 被設定的 info 值,帶進 method 中的 String 參數並執行之,以上例來說就等於執行:
printSomthing("someInfo")
為了方便的掃描有被標記 annotation 的 class, method,這裡使用了 org.reflections.reflections 的 lib
Maven dependency:
<dependencies> <!-- https://mvnrepository.com/artifact/org.reflections/reflections --> <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.10.2</version> </dependency> </dependencies>首先是檔案結構:
接著來看每一個 Class 的內容:
otherpackage.Class1.java
package otherpackage; import customannotation.CustomAnnotation; public class Class1 { @CustomAnnotation(info = "Class1 info") public static void printInfo(String info) { System.out.println("Class1 print info: " + info); } }
otherpackageSubpackage.Class2.java:
package otherpackage.subpackage; import customannotation.CustomAnnotation; public class Class2 { @CustomAnnotation public static void printInfo(String info) { System.out.println("Class2 print info: " + info); } }
Class1.java 和 Class2.java 沒有做什麼特別的事,只是用來測試我們自製 Annotation (@CustomAnnotation) 的 Class 而已,可以注意到,@CustomAnnotation 都加注在了 method 的上面,並且 Class1.java 有設定 info = "Class1 info" 的 info 參數值,而 Class2.java 沒有設定任何值。
CustomAnnotation.java:
package customannotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CustomAnnotation { String info() default "empty info"; }
CustomAnnotation.java 是我們要建立的自製 Annotation,內容非常簡單,只是做了一些基本設定。
main.Test.java:
package main; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Set; import org.reflections.Reflections; import org.reflections.scanners.Scanners; import org.reflections.util.ConfigurationBuilder; import customannotation.CustomAnnotation; public class Test { public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { Reflections reflections = new Reflections(new ConfigurationBuilder() .forPackage("otherpackage") .setScanners(Scanners.MethodsAnnotated) ); Set<Method> foundMethodSet = reflections.getMethodsAnnotatedWith(CustomAnnotation.class); for (Method foundMethod : foundMethodSet) { Class<?> classDeclareMethod = foundMethod.getDeclaringClass(); Object objectInstance = classDeclareMethod.getDeclaredConstructor().newInstance(); CustomAnnotation annotation = foundMethod.getAnnotation(CustomAnnotation.class); //foundMethod.invoke(objectInstance, annotation.info()); // for non-static method, nned to new a instance foundMethod.invoke(null, annotation.info()); //for static method, don't need to new a instance //result : //Class1 print info: Class1 info //Class2 print info: empty info } } }
Test 是主要的 Class,在這裡我們使用了 Reflections.getMethosAnnotatedWith() 找出特定 package 路徑下有被加上 CustomAnnotation 註解的 Method,可以再用 Method.getDeclaringClass() 一併找出 Method 是在哪個 Class 裡,
利 用 Method.getAnnotation() 得到設定在 CustomAnnotation 裡的資料,例如 info 屬性的值,
接著我們利用 Java 的反射 (Reflection) 機制來呼叫 Method ,
如果 Method 是 static 的話可以直接用 invoke 呼叫 ,
如果 Method 不是 static 的話,需要配合建立 Method 所屬的 Class 實體 (Instance)。
最後我們可以看到 Class1 的 method 輸出了 "Class print info: Class1 info",
其中 "Class1 info" 是我們在 Class1 中,設定給 CustomAnnotation 的 info 屬性值。
而 Class2 則輸出了 "Class2 print info: empty info",
其中 "empty info" 是我們為 CustomAnnotatoin 設定的 info 屬性預設值。
參考資料:
沒有留言 :
張貼留言