Annotations is a relatively new technology, it was added to the language in Java5.
An annotation is a meta data that can be attached to a java class, member, function or a parameter.
It gives information about the element that is annotated.
An example is the Deprecated annotation that specifies this function is old and better not used.
@Deprecated public void oldFunction(){ }
Java5 comes with a set of annotations but you can also can create your own.
In this post I will show you how to create your own annotations, use them and also refer to them during runtime.
Steps for creating customized annotations:
1. Creating the annotation interface
First you create the annotation interface which has specific structure.
public @interface InvokeMultiple { int numberOfTimesToInvoke(); }
In this example the name of the annotation is ‘InvokeMultiple’ and it has 1 field ‘numberOfTimesToInvoke’.
Meta-Annotations
Meta annotations are actually annotations being used by annotations.
- @Target – specifies the type pf element this annotation is attached to.
- ElementType.TYPE-can be applied to any element of a class
- ElementType.FIELD-can be applied to a field or property
- ElementType.METHOD-can be applied to a method level annotation
- ElementType.PARAMETER-can be applied to the parameters of a method
- ElementType.CONSTRUCTOR-can be applied to constructors
- ElementType.LOCAL_VARIABLE-can be applied to local variables
- ElementType.ANNOTATION_TYPE-indicates that the declared type itself is an annotation type
- @Retention – specifies the retention level of this annotation.
- RetentionPolicy.SOURCE—Retained only at the source level and will be ignored by the compiler
- RetentionPolicy.CLASS—Retained by the compiler at compile time, but will be ignored by the VM
- RetentionPolicy.RUNTIME—Retained by the VM so they can be read only at run-time
- @Documented – by default annotations are mentioned in java doc, this meta-annotation will make this annotation to be mentioned.
- @Inherited – Indicates that the annotation will automatically be inherited (take a look at the example attached to this post).
Example:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface InvokeMultiple { int numberOfTimesToInvoke(); }
default values
It is also possible to give annotation fields default value.
Example:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface InvokeMultiple { int numberOfTimesToInvoke() default 1; }
2. Using the annotation
Using the annotation is done by attaching the annotation name to the element(class, method, parameter…).
A field value is given in this format (fieldName1=FieldValue1, fieldName2=FieldValue2 ).
Example:
public class TestObject { private String firstName; private String lastName; public TestObject(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } @InvokeMultiple(numberOfTimesToInvoke=3) public void printFirstName(){ System.out.println(firstName); } @InvokeMultiple(numberOfTimesToInvoke=6) public void printLastName(){ System.out.println(lastName); } @InvokeMultiple public void printMessage(){ System.out.println("printed only once"); } public void printSecret(){ System.out.println("this will not be printed"); } }
Notice that the function ‘printMessage()’ is using the default value of the annotation field.
3. Referring to the annotation during runtime
Reading the annotation is done by reflection, but only if your annotation has a retention of RUNTIME.
You can check which annotation an element (class, method, parameter…) is using. And you can also find out the value of the fields of the annotations.
Example:
public static void invokeThis(Object theObject){ try { Method [] methods = Class.forName(theObject.getClass().getName()).getMethods(); for (int i = 0; i < methods.length; i++) { InvokeMultiple invokeMultiple = methods[i].getAnnotation(InvokeMultiple.class); if(invokeMultiple != null){ int numberOfTimesToInvoke = invokeMultiple.numberOfTimesToInvoke(); for (int j = 0; j < numberOfTimesToInvoke; j++) { methods[i].invoke(theObject, null); } } } } catch (Exception e) { e.printStackTrace(); } }
This example above is of a method that receives an object.
By using reflection it goes over all object’s methods and checks if it’s annotated with ‘InvokeMultiple’.
If so, it will invoke that method a number of times according to the value of the annotation field ‘numberOfTimesToInvoke’.
This will not work if your annotation had a Retention other than RUNTIME.
nice post!! thanks
Neatly explained !! Thanks
Good example
Short and clear.
Nice and clear
Very good example…….. Thank you.
Again to reiterate with everyone else, very short and clear example. Thanks.