Annotation
Annotation is most commonly used to store extra information in classes that could be used at runtime by frameworks.An annotation is defined as meta-data type. attributes could be added to store specific values when the annotation is used.
Reflection
Frameworks use the Java reflection to retrieve annotations.Inheritance
Annotation Subclass
It is not possible to extend an annotation to create a annotation type hierarchy. However a new annotation could be created to substitute an annotation with specific attribute values when it is used frequently. Or a new annotation could be used to represent multiple annotations if they are frequently used together.such as:
@Category(value="Food")
public @interface FoodCategory {}
@Action1
@Action2
@Action3
public
Annotation Type Declaration Inheritance
If the @Inherited annotation is used, the Annotation declaration is inherited in class hierarchy only. The annotation declaration on an interface is not inherited.However, the Annotations declared on interfaces are able to be used by their sub types by using reflection to search its type hierarchy. If the interfaces are searched, it is going to be a tree search!
Here are some tests that demo the usages of get annotations in type hierarchies through reflection:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Inherited
public @interface MyAnnotation {
String name();
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@MyAnnotation(name = "usage", value = "extends")
public @interface MyAnnotationExt {
String name();
String value();
}
public class AnnotationUsages {
@MyAnnotation(name = "name1", value = "value1")
public void getAnnotation() {
try {
Class<? extends
AnnotationUsages> cls = this.getClass();
Method method = cls.getMethod("getAnnotation");
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation);
} catch (SecurityException
| NoSuchMethodException e) {
e.printStackTrace();
}
}
@MyAnnotationExt(name = "name2", value = "value2")
public void
getAnnotationOfAnnotation() {
try {
Class<? extends
AnnotationUsages> cls = this.getClass();
Method mth = cls.getMethod("getAnnotationOfAnnotation");
Annotation[] annotations = mth.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
MyAnnotationExt myAnnotationExt = mth.getAnnotation(MyAnnotationExt.class);
annotations = myAnnotationExt.annotationType().getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
} catch (SecurityException
| NoSuchMethodException e) {
e.printStackTrace();
}
}
// Annotations over annotation
@Test
public void
testMethodAnnotations() {
AnnotationUsages usages = new
AnnotationUsages();
usages.getAnnotation();
usages.getAnnotationOfAnnotation();
}
// Annotations over type hierarchy
@Test
public void
testTypeAnnotations() {
MyClass1 cls1 = new MyClass1();
cls1.getTypeAnnotation();
MyClass2 cls2 = new MyClass2();
cls2.getTypeAnnotation();
MyClass3 cls3 = new MyClass3();
cls3.getTypeAnnotation();
MyInterface myInterfaceInstance = new MyClass3();
System.out.println("===MyInterface===");
try {
Class<?> myInterface = myInterfaceInstance.getClass().getInterfaces()[0];
Annotation[] annotations = myInterface.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
} catch (SecurityException
e) {
e.printStackTrace();
}
}
@MyAnnotation(name = "name1", value = "value1")
@MyAnnotationExt(name = "name2", value = "value2")
interface MyInterface {
public void
getTypeAnnotation();
}
@MyAnnotation(name = "name10", value = "value10")
@MyAnnotationExt(name = "name20", value = "value20")
public static class MyClass1 {
public void
getTypeAnnotation() {
try {
System.out.println("===MyClass1===");
Class<? extends MyClass1> cls = this.getClass();
Annotation[] annotations = cls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
} catch (SecurityException
e) {
e.printStackTrace();
}
}
}
public static class MyClass2 extends MyClass1 {
@Override
public void
getTypeAnnotation() {
System.out.println("===MyClass2===");
try {
Class<? extends MyClass2> cls = this.getClass();
Annotation[] annotations = cls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
} catch (SecurityException
e) {
e.printStackTrace();
}
}
}
public static class MyClass3 implements MyInterface {
@Override
public void
getTypeAnnotation() {
System.out.println("===MyClass3===");
try {
Class<? extends MyClass3> cls = this.getClass();
Annotation[] annotations = cls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
} catch (SecurityException
e) {
e.printStackTrace();
}
}
}
}
|
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name1,
value=value1)
@com.americanexpress.ssae.sample.annotation.MyAnnotationExt(name=name2,
value=value2)
@java.lang.annotation.Retention(value=RUNTIME)
@java.lang.annotation.Target(value=[TYPE,
METHOD, PARAMETER, FIELD, ANNOTATION_TYPE])
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=usage,
value=extends)
===MyClass1===
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name10,
value=value10)
@com.americanexpress.ssae.sample.annotation.MyAnnotationExt(name=name20,
value=value20)
===MyClass2===
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name10,
value=value10)
===MyClass3===
===MyInterface===
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name1,
value=value1)
@com.americanexpress.ssae.sample.annotation.MyAnnotationExt(name=name2,
value=value2)
|