Recent Posts

Wednesday, 20 April 2016

Java Annotations

            
      Java Annotations allow us to add metadata information into our source code, although they are not a part of the program itself. Annotations were added to the java from JDK 5. Annotation has no direct effect on the operation of the code they annotate (i.e. it does not affect the execution of the program). Annotation is code about the code, i.e., metadata about the program itself. In other words, organized data about the code, embedded within the code itself. It can be parsed by the compiler, annotation processing tools and can also be made available at run-time too. We have basic java comments infrastructure using which we can add information about the code / logic so that in future, another programmer or the same programmer can understand the code in a better way. Javadoc is an additional step over it, where we add information about the class, methods, and variables in the source code. The way we need to add is organized using syntax. Therefore, we can use a tool and parse those comments and prepare a Javadoc document which can be distributed separately.
      Javadoc facility gives option for understanding the code in an external way, instead of opening the code the Javadoc document can be used separately. An IDE benefit using this javadoc as it is able to render information about the code as we develop. Annotations were introduced in JDK 1.5
     We are talking about metadata multiple times. What is this metadata in java language context? Why we even care about them? Let’s understand the need to metadata with an example.
Below is a source code of class which is declared as final:
                                        public final class MyFinalClass{
                                              //other class members
                                         }
      Now we have ‘final’ keyword in class declaration. And the impact of this declaration is that you can’t extend this class or make a child class of it. How compiler understand this? Simply because of final keyword. Right? Well, this is called metadata.
      “A metadata is data about data. Metadata adds some additional flags on your actual data (i.e. in above case the class MyFinalClass), and in runtime either you or JVM who understand these flags, can utilize this metadata information to make appropriate decisions based on context.”
       In java, we use the annotations to denote metadata. We can annotate classes, interface, methods, parameters and even packages also. We have to utilize the metadata information represented by these annotations in runtime usually.
Annotation Structure
     There are two main components in annotations. First is annotation type and the next is the annotation itself which we use in the code to add meaning. Every annotation belongs to a annotation type.
Annotation Type:
@interface  {
method declaration;
}          
Annotation type is very similar to an interface with little difference.
  •  We attach ‘@’ just before interface keyword.
  •  Methods will not have parameters.
  •  Methods will not have throws clause.
  •  Method return types are restricted to primitives, String, Class, enums, annotations, and arrays of the preceding types.
  •  We can assign a default value to method.
Meta Annotations
      Annotations itself is meta information then what is meta annotations? As you have rightly guessed, it is information about annotation. When we annotate a annotation type then it is called meta annotation. For example, we say that this annotation can be used only for methods.
@Target(ElementType.METHOD)
public @interface MethodInfo { }

Annotation Types
Documented
     When an annotation type is annotated with @Documented then wherever this annotation is used those elements should be documented using Javadoc tool.
Inherited
     This meta annotation denotes that the annotation type can be inherited from super class. When a class is annotated with annotation of type that is annotated with Inherited, then its super class will be queried till a matching annotation is found.
Retention
      You can specify for your custom annotation if it should be available at runtime, for inspection via reflection. You do so by annotating your annotation definition with the @Retention annotation. When an annotation type is annotated with meta annotation Retention, RetentionPolicy has three possible values:
            @Retention(RetentionPolicy.RUNTIME)
            public @interface Developer {
                        String value();
            }
1. Class
When the annotation value is given as class then this annotation will be compiled and included in the class file.
2. Runtime
The value name itself says, when the retention value is ‘Runtime’ this annotation will be available in JVM at runtime. We can write custom code using  reflection package and parse the annotation. I have give an example below.
3. Source
This annotation will be removed at compile time and will not be available at compiled class.
4. Target
This meta annotation says that this annotation type is applicable for only the element (ElementType) listed. Possible values for ElementType are, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE.
@Target(ElementType.FIELD)
public @interface FieldInfo { }
Built-in Java Annotations
     @Documented, @Inherited, @Retention and @Target are the four available meta annotations that are built-in with Java. Apart from these meta annotations we have the following annotations.
@Override
    When we want to override a method, we can use this annotation to say to the compiler we are overriding an existing method. If the compiler finds that there is no matching method found in super class then generates a warning. This is not mandatory to use @Override when we override a method. But I have seen Eclipse IDE automatically adding this @Override annotation. Though it is not mandatory, it is considered as a best practice.
Eg: 
public class MySuperClass {
    public void doTheThing() {
        System.out.println("Do the thing");
    }
}

public class MySubClass extends MySuperClass{
    @Override
    public void doTheThing() {
        System.out.println("Do it differently");
    }
}
@Deprecated
    When we want to inform the compiler that a method is deprecated we can use this. So, when a method is annotated with @Deprecated and that method is found used in some place, then the compiler generates a warning. When an element is deprecated, it should also be documented using the Javadoc @deprecated tag, as shown in the following example. Make a note of case difference with @Deprecated and @deprecated. @deprecated is used for documentation purpose.
/**
 * @deprecated
 * reason for why it was deprecated
 */
@Deprecated
public void anyMethodHere(){
    // Do something

}
Now, whenever any program would use this method, the compiler would generate a warning.
@SuppressWarnings
    This is like saying, “I know what I am doing, so please shut up!” We want the compiler not to raise any warnings and then we use this annotation. This annotation instructs compiler to ignore specific warnings. For example in the below code, I am calling a deprecated method (lets assume that the method deprecatedMethod() is marked with @Deprecated annotation) so the compiler should generate a warning, however I am using @SuppressWarnings annotation that would suppress that deprecation warning.
@SuppressWarnings("deprecation")
    void myMethod() {
        myObject.deprecatedMethod();

}
Creating Custom Annotations
     Annotations are created by using @interface, followed by annotation name as shown in the below example. An annotation can have elements as well. They look like methods. For example in the below code, we have four elements. We should not provide implementation for these elements. All annotations extends java.lang.annotation.Annotation interface. Annotations cannot include any extends clause.
Eg:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomAnnotation{
    int studentAge() default 18;
    String studentName();
    String stuAddress();
    String stuStream() default "CSE";
}
Note: All the elements that have default values set while creating annotations can be skipped while using annotation. For example if I’m applying the above annotation to a class then I would do it like this:

@MyCustomAnnotation(
    studentName="Chaitanya",
    stuAddress="Agra, India"
)
public class MyClass {
...
}
    As you can see, we have not given any value to the studentAge and stuStream elements as it is optional to set the values of these elements (default values already been set in Annotation definition, but if you want you can assign new value while using annotation just the same way as we did for other elements). However we have to provide the values of other elements (the elements that do not have default values set) while using annotation.
Note: We can also have array elements in an annotation. This is how we can use them:
Annotation definition:

@interface MyCustomAnnotation {
    int      count();
    String[] books();
}

Usage:

@MyCustomAnnotation(
    count=3,
    books={"C++", "Java"}
)
public class MyClass {


}
 Lets back to the topic again: In the custom annotation example we have used these four annotations: @Documented, @Target, @Inherited & @Retention. Lets discuss them in detail.
@Documented
     @Documented annotation indicates that elements using this annotation should be documented by JavaDoc. For example:

java.lang.annotation.Documented
@Documented
public @interface MyCustomAnnotation {
  //Annotation body
}

@MyCustomAnnotation
public class MyClass { 
     //Class body
}

While generating the javadoc for class MyClass, the annotation @MyCustomAnnotation would be included in that.
@Target
     It specifies where we can use the annotation. For example: In the below code, we have defined the target type as METHOD which means the below annotation can only be used on methods.

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
public @interface MyCustomAnnotation {

}

public class MyClass {
   @MyCustomAnnotation
   public void myMethod()
   {
       //Doing something
   }
}

Note: 1) If you do not define any Target type that means annotation can be applied to any element.
2) Apart from ElementType.METHOD, an annotation can have following possible Target values.
ElementType.METHOD
ElementType.PACKAGE
ElementType.PARAMETER
ElementType.TYPE
ElementType.ANNOTATION_TYPE
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.FIELD
@Inherited
     The @Inherited annotation signals that a custom annotation used in a class should be inherited by all of its sub classes. For example:

java.lang.annotation.Inherited

@Inherited
public @interface MyCustomAnnotation {

}

@MyCustomAnnotation
public class MyParentClass { 
  ... 
}

public class MyChildClass extends MyParentClass { 
   ... 
}

Here the class MyParentClass is using annotation @MyCustomAnnotation which is marked with @inherited annotation. It means the sub class MyChildClass inherits the @MyCustomAnnotation.
@Retention
     It indicates how long annotations with the annotated type are to be retained.

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface MyCustomAnnotation {
    
}

Here we have used RetentionPolicy.RUNTIME. There are two other options as well. Lets see what do they mean:
RetentionPolicy.RUNTIME: The annotation should be available at runtime, for inspection via java reflection.
RetentionPolicy.CLASS: The annotation would be in the .class file but it would not be available at runtime.
RetentionPolicy.SOURCE: The annotation would be available in the source code of the program, it would neither be in the .class file nor be available at the runtime.


That’s all for this topic “Java Annotations”. Should you have any questions, feel free to drop a line below.

No comments:

Post a Comment