Saturday, September 28, 2013

Java Annotations - An Overview

Introduction

  • Introduced in JDK 1.5
  • One of the biggest ever feature added in Java.
  • A form of syntactic metadata that can be added to Java source code. Its basically Data about Data.
  • Annotations don't do anything on their own, they don't do any processing. They act like a modifier and become useful only when they are processed.
  • Annotations can be processed at compile time, run time or deployment time.
  • Annotations are tags that we insert into our code, to be processed by tools like compiler, deployment tools or other external packages. Annotations are part of the code.
  • Can be embedded in class files generated by the compiler and may be retained by the Java VM to be made retrievable at run-time.(Reference: Retention policy)
  • Prior to Annotations, Java provided only ad-hoc and non-standardized mechanism, including Serializable interface (other market interfaces), transient modifier, Javadoc comments, @deprecated tag in comments.One of the main reasons for adding annotation and metadata to the Java platform is to enable development and runtime tools to have a common infrastructure.
  • Annotations are part of java code, Java Docs are not. 
  • java.lang.annotations package provides library support for the Java programming language annotation facility.
  • Normally a developer needn't create Annotations.
  • Annotation-based programming is an extensible mechanism for generating application artifacts, packaging the application, and readying the application for execution.
  • Annotation-based programming offers a set of tags and a processing mechanism that allow you to embed additional metadata into code. Application then uses this additional metadata to derive the artifacts required to execute the application in a J2EE environment.

Defining Annotations:

     public @interface TestAnno
     {
        String str(); // It can never has any parameters.
        int count();
     } 

Implementation Key points:

  • @interface keyword is used to define annotations.
  • Annotation types are a form of interface.
  • Annotation elements must be compile time constant values.
  • There is no restriction of the type of annotation element.
  • All annotations consist solely of method declarations. These method declarations are called elements.
  • The declarations must not have any formal parameters or a throw clause.
  • java.lang.annotation.Annotation is super-interface for all annotations.
  • Annotations cannot include the extends clause.
  • Annotations can be applied to any declaration, ex. classes, methods, fields, parameters, enum, constants or even an annotation type.
  • There is a default value element in the annotations.
  • Annotations cannot use Generics, no generic member type, no type parameters.
     public class TestClass
     {
        @TestAnno (str="MyFirstAnnoTest", count=1001) 

        // When a element is given a value only name is used, 
        // paranthesis are not used.
        public static void main(String[] args)
        {
                ...
        }
     } 

  • If the annotation has no elements, then the parentheses can be omitted. Ex @Override.
  • If there is just one element named value, then the name can be omitted. Ex
    • @SuppressWarnings(value = "unchecked")
    • @SuppressWarnings("unchecked")
  • It is also possible to use multiple annotations on the same declaration: 
    • @TestAnno (str="MyFirstAnnoTest", count=1001)      
      @SuppressWarnings("unchecked")
      class  TestClass  { ... }
       

Annotation Uses:

  • Annotations helps moving away redundant code, remove config xml (ex. deployment descriptor), adds extra checks (ex. @override).
  • Provide information to Compiler - 
    • To detect errors or suppress warnings (@Deprecated, @Override, @SuppressWarning)
  • Compile-time and deployment-time processing -
    • Software tools can process annotation information to generate code, XML files, and so forth. Ex @WebServlet, @WebInitParam, @WebFilter, @WebListener etc.
  • Runtime processing - 
    • Marker Annotations

Default Value for Annotation elements

  • We can provide default values to annotations, that will be assigned if no value is specified.
  • A default value is specified by adding a default clause to a member's declaration.
  • Syntax:
    • type member() default default-value
    • default-value must be type compatible with member type.
       public @interface TestAnno
       {
          String str() default "testString" ; 

          int count() default -1 ;
       } 

Marker Annotations

  • Similar in concept with Marker interface - no member methods with sole purpose of marking a declaration.

Single-Member Annotations

  • As the name suggests, only one annotation contains only one member. 
  • member name should be value.
  • Uniqueness - allows to use shorthand, no need to specify the name of the member.
    public @interface TestSingleAnno
    {
       String value() ;

    }
    @TestSingleAnno("Testing Single Annotation")
    public static void main(Sting[] args)
    {
        ...
    }

Java SE Predefined Annotations:

  • @Deprecated
    • Defined in java.lang package.
    • Introduced in Java 1.5
    • When @Deprecated is used, documentation (javadoc @deprecated comment) should reflect why open is deprecated and what to use instead.
  • @Override
    • Defined in java.lang package. 
    • Introduced in Java 1.5  
    • If a method marked with @Override fails to correctly override a method, the compiler throws an error.
    • It helps to prevent errors. 
  • @SuppressWarning 
    • Defined in java.lang package. 
    • Introduced in Java 1.5  
    • Instructs the compiler to suppress specific warnings that it would otherwise generate.
    • Warnings like unused variables, deprecated methods will be suppressed by compiler. 
    • Ex. @SuppressWarnings("deprecation")
    • Ex. @SuppressWarnings({"unchecked", "deprecation"})
  • @SafeVarargs
    • Defined in java.lang package.
    • Introduced in Java 1.7
    • It asserts that the code does not perform potentially unsafe operations on its varargs parameter. 
    • Unchecked warnings relating to varargs usage are suppressed.
  • @FunctionalInterface
    • Defined in java.lang package.
    • Introduced in Java 1.8
    • An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification.
    • Conceptually, a functional interface has exactly one abstract method.
    • However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a FunctionalInterface annotation is present on the interface declaration.
    • If a type is annotated with this annotation type, compilers are required to generate an error message unless:
      • The type is an interface type and not an annotation type, enum, or class.
      • The annotated type satisfies the requirements of a functional interface.

Meta-Annotations

Annotations that apply to other annotations.
It is information about annotation.There are several meta-annotation types defined in java.lang.annotati
  • @Retention 
    • Specifies how the marked annotation is stored, at what point, its discarded.
    • Java defines 3 such policies encapsulated in java.lang.annotation.RetentionPolicy enumeration - SOURCE, CLASS, RUNTIME.
    • SOURCE - Retained only in source file and discarded during compilation.
    • CLASS - Stored in .class file during compilation, but its not available through JVM during runtime.
    • RUNTIME - Stored in .class file during compilation, and available through JVM during runtime. It offers the greatest annotation persistence.
    • Default Retention level is CLASS. If no Retention annotation is present on an annotation type declaration, the retention policy defaults to RetentionPolicy.CLASS
    • Ex. @Retention(RetentionPolicy.RUNTIME) 
  • @Documented
    • Indicates whenever the specified annotation is used those elements should be documented using the Javadoc tool. 
    • By default, annotations are not included in Javadoc.
    • To make the information in @TestAnno appear in Javadoc-generated documentation, you must annotate the @TestAnno definition with the @Documented annotation:
        // import this to use @Documented
        import java.lang.annotation.*;

        @Documented
        public @interface TestAnno 
        { 
           String str(); // It can never has any parameters. 
           int count(); 
        }

  • @Target
    • Indicates the kinds of program element to which an annotation type is applicable.
    • If a Target meta-annotation is not present on an annotation type declaration, the declared type may be used on any program element.
    • A target annotation specifies one of the following element types as its value:
      • ElementType.ANNOTATION_TYPE can be applied to an annotation type.
      • ElementType.CONSTRUCTOR can be applied to a constructor.
      • ElementType.FIELD can be applied to a field or property.
      • ElementType.LOCAL_VARIABLE can be applied to a local variable.
      • ElementType.METHOD can be applied to a method-level annotation.
      • ElementType.PACKAGE can be applied to a package declaration.
      • ElementType.PARAMETER can be applied to the parameters of a method.
      • ElementType.TYPE can be applied to any element of a class.
       Ex. @Target({ElementType.FIELD, ElementType.METHOD, 
                    ElementType.FIELD})           

           public @interface TestAnno {
            ...

           }
 

           @Target(ElementType.ANNOTATION_TYPE)
           public @interface TestAnno {
            ...
   
       }
  •  @Inherited
    • Indicates that the annotation type is automatically inherited from the super class.
    • This annotation applies only to class declarations.
    • By Default a class doesn't inherit annotations of its super class.
    • When the user queries the annotation type and the class has no annotation for this type, the class' superclass is queried for the annotation type.

Java 8 Enhancements

Type Annotations and Pluggable Type Systems

  • Before the Java SE 8 release, annotations could only be applied to declarations.
  • As of the Java SE 8 release, annotations can also be applied to any type use.
  • A few examples of where types are used are class instance creation expressions (new), casts, implements clauses, and throws clauses.
  • This form of annotation is called a type annotation, following are few examples:
    new @Interned MyObject(); //Class instance creation 

    myString = (@NonNull String) str; //Type cast 

    @NonNull String str;  

    class UnmodifiableList<T> implements
   
    @Readonly List<@Readonly T> { ... } //implements clause 


    void monitorTemperature() throws
         @Critical TemperatureException { ... } //Thrown exception declaration

  • Type annotations were created to support improved analysis of Java programs way of ensuring stronger type checking. 
  • The Java SE 8 release does not provide a type checking framework. 
  • It allows you to write (or download) a type checking framework that is implemented as one or more pluggable modules that are used in conjunction with the Java compiler.

@Repeatable

  • Indicates that the marked annotation can be applied more than once to the same declaration or type use.
  •  There are situations where you want to apply same annotation multiple times to a declaration or type use. Following are few examples:
    • A Project could fall under several project categories.
    • A process needs to be scheduled for multiple time.
    • An event could be observed by multiple roles.
    //custom annotation without repeatable
    public @interface Schedule { ... }
 

    //container annotation for repeatable
    public @interface Schedules {
         Schedule[] value;
    }
 

    //custom annotation with repeatable
    //The value of @Repeatable meta-annotation is container annotation.
    @Repeatable(Schedules.class)
    public @interface Schedule { ... }