Showing posts with label Annotation. Show all posts
Showing posts with label Annotation. Show all posts

Monday, 9 May 2011

Annotating an annotations

When you start writing your own annotation types, the main purpose of your annotation types is to provide basic documentation. Also you write annotation types that are specific to a certain member type, or perhaps a certain set of member types. This requires you to supply some sort of metadata on your annotation type, so that the compiler can enforce the annotation’s intended functionality.

The most obvious meta-annotation is one that allows you to indicate which program elements can have annotations of the defined type.
Such meta-annotation is called Target. We have alread discussed @Target annotation here. You should know about another new class called ElementType. This enum defines the various program elements that an annotation type can target.

 

ElementType enum

package java.lang.annotation;

public enum ElementType {
TYPE, // Class, interface, or enum (but not annotation)
FIELD, // Field (including enumerated values)
METHOD, // Method (does not include constructors)
PARAMETER, // Method parameter
CONSTRUCTOR, // Constructor
LOCAL_VARIABLE, // Local variable or catch clause
ANNOTATION_TYPE, // Annotation Types (meta-annotations)
PACKAGE // Java package
}


The enumerated values in exampel above are obvious. When you use the Target meta-annotation, you supply it at least one of these enumerated values and indicate
which program elements the annotated annotation can target. Now we have to use target annotation.

 

Using Target annotation to annotate your annotation


package com.vaani.annotations.target; 
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

// Using the Target meta-annotation
/**
* Annotation type to indicate a task still needs to be completed
*/
@Target({ElementType.TYPE,
ElementType.METHOD,
ElementType.CONSTRUCTOR,
ElementType.ANNOTATION_TYPE})
public @interface TODO {
String value();
}

Now the Java compiler will apply TODO only to types, methods, constructors, and other annotation types.
This helps you ensure that nobody else uses your custom annotation type and misapplies it.


Saturday, 30 April 2011

Every annotation in JDK 1.5 onwards has a corresponding class

Every annotation in JDK 1.5 onwards has a corresponding class. For example, the @override annotation which tells that a method is an overridden version of the method inherited from the super class, has a corresponding Override.class.  

Similarly we have the Deprecated.class for the @deprecated annotation. We can see the contents of the corresponding source file to check what all attributes/parameters are being supported by the @override annotation. The Override.class has the following contents:

/  (version 1.5 : 49.0, no super bit)
@java.lang.annotation.Target(value={java.lang.annotation.ElementType.METHOD})
@java.lang.annotation.Retention(value=java.lang.annotation.RetentionPolicy.SOURCE)
public abstract @interface java.lang.Override extends java.lang.annotation.Annotation {

}


This suggests us that the annotation @Override can have two attributes viz Target and Retention. The value accepted by Target attribute is of type METHOD and of Retention is SOURCE.

The decompiled code of the Override.class is:

package java.lang;
import java.lang.annotation.Annotation;
// Referenced classes of package java.lang:
// Object

public interface Override extends Annotation {
}


This is applicable to all annotations that you may come across in various frameworks/tools. All annotations in Spring, Hibernate, JPA are backed by corresponding classes. If you decompile the code which makes use of annotations, you will not see any reference to annotation classes as the dependency with annotations is resolved at compile time only. Thus annotations are Meta-data for the compiler which it makes use of to perform common functions for developers thus easing the life of a Java application developer.

Wednesday, 27 April 2011

Obtaining annotations at runtime using reflection

You can use getAnnotation method on Class of object, which has annotation attached to it.

Defining an annotation

package com.vaani.annotations;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface HelloAnno {
String value();
String greetTo();
}

 

Using the annotations


Note that I have kept value as German words, corresponding to greetTo which is in english lanaguage.

@HelloAnno(value = "Gooten Morgen", greetTo = "GoodMorning")
public class AnnotationUser{
@HelloAnno(value = "Gooten Tag", greetTo = "Hi")
public void sayHi() {
}
//
@HelloAnno(value = "Gute Nacht", greetTo = "GoodNight")
public void sayHello() {
try {
Method m = getClass().getMethod("sayHello");
HelloAnno anno = m.getAnnotation(HelloAnno.class);

System.out.println(anno.value() + " " + anno.greetTo());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}


 


Method to print all annotation




public static void printAnnotations(Class clazz){
Class clazz = demo.getClass();
Annotation[] annotations = clazz.getAnnotations();
for (Annotation anno : annotations) {
       System.out.println("Annotation Type: " + anno.annotationType());

//Prints Annotation Type: interface com.vaani.annotations


}

HelloAnno anno = (HelloAnno) clazz.getAnnotation(HelloAnno.class);
System.out.println("Anno Value : " + anno.value());
System.out.println("Anno GreetTo: " + anno.greetTo());
//Outputs
Anno value : Gooten Morgen
Anno GreetTo : GoodMorning


try {
Method m = clazz.getMethod("sayHi");

anno = m.getAnnotation(HelloAnno.class);
System.out.println("Anno Value : " + anno.value());
System.out.println("Anno GreetTo: " + anno.greetTo());

 

//Outputs
Anno value : Gooten Tag
Anno GreetTo : Hi



} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}





Runner or tester class to show annotation:


public static void main(String[] args) {
GettingAnnotation demo = new GettingAnnotation();
Class clazz = demo.getClass();
printAnnotation(clazz);
}

Annotations in java5

  1. Java defines seven built-in annotations.
  2. Four are imported from java.lang.annotation: @Retention, @Documented, @Target, and @Inherited.
  3. Three, @Override, @Deprecated, and @SuppressWarnings, are included in java.lang.
Seeing them one by one:
@Override
@Deprecated
@SuppressWarnings
@Retention
@Documented
@Target
@Inherited

Target annotation in java

Target indicates which program element(s) can be annotated using instances of the annotated annotation type. The value of Target is one of the members of the java.lang.annotation.
ElementType enum:
  1. ANNOTATION_TYPE. The annotated annotation type can be used to annotate
    annotation type declaration.
  2. CONSTRUCTOR. The annotated annotation type can be used to annotate
    constructor declaration.
  3. FIELD. The annotated annotation type can be used to annotate field declaration.
  4. LOCAL_VARIABLE. The annotated annotation type can be used to annotate local
    variable declaration.
  5. METHOD. The annotated annotation type can be used to annotate method declaration.
  6. PACKAGE. The annotated annotation type can be used to annotate package declarations.
  7. PARAMETER. The annotated annotation type can be used to annotate parameter declarations.
  8. TYPE. The annotated annotation type can be used to annotate type declarations.
@Target(value=METHOD)
You can have multiple values in the Target annotation.


@Target(value={TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,
LOCAL_VARIABLE})

Retention annotation in java

  1. @Retention indicates how long annotations whose annotated types are annotated
    @Retention are to be retained.
  2. The value of @Retention can be one of the members of the java.lang.annotation.
    RetentionPolicy enum:
  1. SOURCE. Annotations are to be discarded by the Java compiler.
  2. CLASS. Annotations are to be recorded in the class file but not be retained by the JVM.
    This is the default value.
  3. RUNTIME. Annotations are to be retained by the JVM so you can query them using reflection.

Inherited annotation

  1. Use Inherited to annotate an annotation type, any instance of the annotation type will be inherited.
  2. Use Inherited to annotate a class, the annotation will be inherited by any subclass of the annotated class. If the user queries the annotation type on a class declaration, and the class declaration has no annotation of this type, then the class's parent class will automatically be queried for the annotation type. This process will be repeated until an annotation of this type is found or the root class is reached.

Using this annotation

Suppose that you use your custom annotation called InProgress to mark a class as being in progress. If the Documented meta-annotation is applied correctly, then this will show up in the Javadoc. All is well till here.

Suppose you write a new class and extend the in-progress class. Now remember one this: the superclass is in progress. What about the subclass? For subclass, there will be no indication even in its documentation, that it is incomplete. One would expect to see the InProgress annotation carried through to subclasses. But its not done here. So this is where @Inherited comes into picture.

package com.vaani.annotations.inherited; 
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

// Using the Inherited meta-annotation
/**
* Marker annotation to indicate that a method or class
* is still in progress.
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }

Documented annotation

  1. Documented is a marker annotation type used to annotate the declaration of an annotation type so that instances of the annotation type will be included in the documentation.
  2. Override annotation type is not annotated using Documented.
  3. Deprecated annotation type is annotated @Documented.

SuppressWarnings annotation : Suppressing the compiler warnings

SuppressWarnings is used to suppress compiler warnings. You can apply @SuppressWarnings to types, constructors, methods, fields, parameters, and local variables.

The following are valid parameters to @SuppressWarnings:
  1. unchecked.suppress warnings from an unchecked call or an unchecked cast
  2. path. suppress warnings about nonexistent path (classpath, sourcepath, etc) directories.
  3. serial. suppress warnings about missing serialVersionUID definitions on serializable classes.
  4. finally.suppress warnings about finally clauses that cannot complete normally.
  5. fallthrough. Check switch blocks for fall-through cases.
And there are many mores...whcih are discussed later.

    Examples


      public class Main {
          @SuppressWarnings(value={"deprecation"})
          public static void main(String[] args) {
             
      DeprecatedTest test = new DeprecatedTest();
              test.serve();

          }
      }



      Example to suppress Unchecked
      i.e it will suppress the warnings from an unchecked call or an unchecked cast
      @SuppressWarnings("unchecked")
        public static void main(String[] args) {
          ArrayList data = new ArrayList();
          data.add("hello");
          data.add("world");

          Iterator it = data.iterator();
          while (it.hasNext()) {
            System.out.println(it.next());
          }
        }


      Example to suppress 2 warnings

      Suppress 2 warnings - ie.for unchecked cast or call  OR serializable class does not define a serialVersionUID
      @SuppressWarnings (value={"unchecked""serial"})
      public class SuppressWarningsTest implements Serializable {
          public void openFile () {
              ArrayList a = new ArrayList ();
              File file = new File ("X:/java/doc.txt");
          }
      }


      Valid warning types

      Though above only few warnings were shown, but sun JDK uses a larger set of strings in the compiler.  You can determine the current set by executing:
      javac -X
      which will show you (among other things) the valid settings for -Xlint. 

      For example, Sun JDK 1.5 shows:
      • all  - suppress all warnings from this code
      • deprecation  - suppress warnings from using deprecated code
      • unchecked - suppress warnings from an unchecked call or an unchecked cast
      • fallthrough - suppress warnings if a switch falls through without finding a valid case (and no default)
      • path -Warn about nonexistent path (classpath, sourcepath, etc) directories.
      • serial - suppress warnings if a Serializable class does not define a serialVersionUID
      • finally - suppress warnings from return within a finally (which will ignore return with the try)

      And Sun JDK 1.6 adds:
      • cast
      • divzero - suppress warnings if integer divide by zero is detected
      • empty
      • overrides
      • none

      IDEs and static analysis tools typically support a large number of other possible values for @SuppressWarnings.  These values correspond to specific static analysis checks performed by the IDE.


      Eclipse

      The Eclipse warning values for Eclipse 3.3 are documented in the JDT docs.
      • all - suppress all warnings
      • boxing - suppress warnings relative to boxing/unboxing operations
      • cast - suppress warnings relative to cast operations
      • dep-ann - suppress warnings relative to deprecated annotation
      • deprecation - suppress warnings relative to deprecation
      • fallthrough - suppress warnings relative to missing breaks in switch statements
      • finally - suppress warnings relative to finally block that don't return
      • hiding - suppress warnings relative to locals that hide variable
      • incomplete-switch - suppress warnings relative to missing entries in a switch statement (enum case)
      • nls - suppress warnings relative to non-nls string literals
      • null - suppress warnings relative to null analysis
      • restriction - suppress warnings relative to usage of discouraged or forbidden references
      • serial - suppress warnings relative to missing serialVersionUID field for a serializable class
      • static-access - suppress warnings relative to incorrect static access
      • synthetic-access - suppress warnings relative to unoptimized access from inner classes
      • unchecked - suppress warnings relative to unchecked operations
      • unqualified-field-access - suppress warnings relative to field access unqualified
      • unused - suppress warnings relative to unused code


      Deprecated annotation

      Deprecated is a marker annotation type that can be applied to a method or a type (class/interface) to
      indicate that the method or type is deprecated. Deprecating a method:

      public class DeprecatedTest {
        @Deprecated
        public void serve() {

        }

      }
      If you use or override a deprecated method, you will get a warning at compile time.
      public class DeprecatedTest2 {
        public static void main(String[] args) {
          DeprecatedTest test = new DeprecatedTest();
          test.serve();
        }
      }

      class DeprecatedTest {
        @Deprecated
        public void serve() {

        }

      }


      Override Annotation

      Note that it is the most used annotation...
      Override is a marker annotation type that can be applied to a method to indicate to the compiler that the method overrides a method in a superclass. This annotation type guards the programmer against making a mistake when overriding a method. For example, consider this class Parent:
      class Parent {
          public float calculate (float a, float b) {
              return a * b;
          }
      }
      Whenever you want to override a method, declare the Override annotation type 

      before the method:

      public class Child extends Parent {
          @Override
          public int calculate (int a, int b) {
              return (a + 1* b;
          }
      }

      Restrictions on annotations

      1. No annotation can inherit another.
      2. All methods declared by an annotation must be without parameters.
      3. Annotations cannot be generic.
      4. They cannot specify a throws clause.
      Also they are allowed to return only :
      • primitives
      • String
      • Class
      • enum
      • array of the above types

      Creating custom annotations in java


      Here are some rule to consider when defining an annotation type:
      1. Annotation declaration should start with an 'at' sign like @, following with an interface keyword, following with the annotation name.
        eg.
        public @interface MyAnnotation
      2. Method declarations should not have any parameters.
      3. Method declarations should not have any throws clauses.
      4. Return types of the method should be one of the following:
        • primitives
        • String
        • Class
        • enum
        • array of the above types


      Example to Define an Annotation (Annotation Type)

      public @interface MyAnnotation {
      String doSomething();
      }

      Example to Annotate Your Code (Annotation)

      MyAnnotation (doSomething="What to do")
      public void mymethod() {
      ....
      }

      What are annotations in java

      Annotations are notes in Java programs to instruct the Java compiler to do something. Java provides three standard annotations and four standard meta-annotations.
      1. An annotation type is a special interface type.
      2. An annotation is an instance of an annotation type.
      3. An annotation type has a name and members.
      4. The information contained in an annotation takes the form of key/value pairs.
      5. There can be zero or multiple pairs and each key has a specific type.
      6. It can be a String, int, or other Java types.

      Java Annotation Types

      Annotation can be classified in 2 ways :
      1. Based on what they are annotating
      2. Based on the number of arguments
      Based on what they are annotating
      There are two types of annotations available with JDK5:
      • Simple annotations: These are the basic types supplied with Tiger, which you can use to annotate your code only; you cannot use those to create a custom annotation type.
      • Meta annotations: These are the annotation types designed for annotating annotation-type declarations. Simply speaking, these are called the annotations-of-annotations.

      Based on the number of arguments
      There are three annotation types:


      Marker
      Marker type annotations have no elements, except the annotation name itself.

      Example:
      public @interface MyAnnotation {
      }
      Usage:
      @MyAnnotation
      public void mymethod() {
      ....
      }

      Single-Element
      Single-element, or single-value type, annotations provide a single piece of data only. This can be represented with a data=value pair or, simply with the value (a shortcut syntax) only, within parenthesis.
      Example:
      public @interface MyAnnotation
      {
      String doSomething();
      }
      Usage:
      @MyAnnotation ("What to do")
      public void mymethod() {
      ....
      }

      Full-value or multi-value
      Full-value type annotations have multiple data members. Therefore, you must use a full data=value parameter syntax for each member.
      Example:
      public @interface MyAnnotation {
      String doSomething();
      int count; String date();
      }
      Usage:
      @MyAnnotation (doSomething="What to do", count=1,
      date="09-09-2005")
      public void mymethod() {
      ....
      }

      Sunday, 17 April 2011

      What is a java marker interface?

      Java marker interface has no members in it. Marker interface ‘was’ used as a tag to inform a message to the java compiler.

      Java Marker Interface Examples:
      java.lang.Cloneable
      java.io.Serializable
      java.util.EventListener

      Lets take the java.io.Serializable marker interface. It doesnot has any members defined it it. When a java class is to be serialized, you should intimate the java compiler in some way that there is a possibility of serializing this java class. In this scenario, marker interfaces are used. The java class which may be serialized has to implement the java.io.Serializable marker interface. In such way, we are intimating the java compiler.

      From java 1.5, the need for marker interface is eliminated by the introduction of the java annotation feature. So, it is wise to use java annotations than the marker interface. It has more feature and advantages than the java marker interface.