Thursday, May 1, 2008

Java Annotations

Annotations in General
Basically it is the Metadata a syntactitcal way of adding metadata to source doe
Differences in computer languages have given rise to a variety of words for programmer-added metadata, including annotation (Java, Python), attribute (C#), pragma (C), and metadata (HTML).

Java Annotations
Annotations provide data about a program that is not part of the program itself. They have no direct effect on the operation of the code they annotate.Annotations are modifiers you can add to your code and apply to package declarations, type declarations, constructors, methods, fields, parameters, and variables.

JSR 175, A Metadata Facility for the Java Programming Language, gives more details on it.

The Interface java.lang.annotation.Annotation is extended by all annotation types. Note that an interface that manually extends this one does not define an annotation type. Also note that this interface does not itself define an annotation type.

J2SE 5 comes with following prebuilt annotations...

(1) java.lang.Overrides - If a method is decorated with this annotation type but does not override a superclass method, then the compiler will generate an error message... may be if one gives incorrect argument type then function will be overloaded so its better use this.
Should be used only on methods (not on classes, package declarations, or other constructs)

@Override
interface Closable {
void close();
}

class File implements Closable {
@Override
public void close() {
//... close this file...
}
}

The compiler generates an error complaining that File.close doesn't override any method from its superclass. This is because it is not overriding Closable.close, it is implementing it!

While it's not required to use this annotation when overriding a method, it helps to prevent errors. If a method marked with @Override fails to correctly override a method in one of its superclasses, the compiler generates an error.


(2) java.lang.annotation.Documented
This annotation indicates that the annotation to which this is applied is to be documented by javadoc and similar tools. Note that this annotation is just a hint, and a tool can ignore the annotation if it desires to do so.

(3) java.lang.Deprecated
This annotation provides a hint to the Java compiler to warn users if they use the class, method, or field annotated with this annotation.
When an element is deprecated, it should also be documented using the Javadoc @deprecated tag, as shown in the following example. The use of the "@" symbol in both Javadoc comments and in annotations is not coincidental—they are related conceptually. Also, note that the Javadoc tag starts with a lowercase "d" and the annotation starts with an uppercase "D".

// Javadoc comment follows
/**
* @deprecated
* explanation of why it was deprecated
*/
@Deprecated
static void deprecatedMethod() { }
}


(4) java.lang.annotation.Inherited
Indicates that an annotation type is automatically inherited. If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class's superclass will automatically be queried for the annotation type. This process will be repeated until an annotation for this type is found, or the top of the class hierarchy (Object) is reached. If no superclass has an annotation for this type, then the query will indicate that the class in question has no such annotation.


(5) java.lang.annotation.Retention
The Retention annotation takes a single parameter that determines the decorated annotation's availability. The values of this parameter are:

  1. RetentionPolicy.SOURCE: The decorated annotation is available at the source code level only
  2. RetentionPolicy.CLASS: The decorated annotation is available in the source code and compiled class file, but is not loaded into the JVM at runtime
  3. RetentionPolicy.RUNTIME: The decorated annotation is available in the source code, the compiled class file, and is also loaded into the JVM at runtime

By default, all annotations are available at the source level only.

(6) java.lang.annotation.Target
This annotation is used to indicate the type of program element (such as a class, method, or field) to which the declared annotation is applicable. If the Target annotation is not present on an annotation type declaration, then the declared type may be used on any program element. If the Target annotation is present, then the compiler will enforce the specified usage restriction. Legal values for the Target annotation are contained in the java.lang.annotation.ElementType enumeration.

(7) SuppressWarnings

@SuppressWarnings("deprecation")
void useDeprecatedMethod() {
objectOne.deprecatedMethod(); //deprecation warning - suppressed
}

Every compiler warning belongs to a category. The Java Language Specification lists two categories: "deprecation" and "unchecked." The "unchecked" warning can occur when interfacing with legacy code written before the advent of generics (discussed in the lesson titled "Generics"). To suppress more than one category of warnings, use the following syntax:

@SuppressWarnings({"unchecked", "deprecation"})

consider the following code:

int a;
Object object = new Object();

I declared two variables and did nto use them in my code. When I compiled the code, I got 2 warnings:

The local variable a is never read
The local variable object is never read

To remove the warnings, I will use the @SuppressWarnings annotation.

@SuppressWarnings("unused")
Object object = new Object();
@SuppressWarnings("unused")
int a;

// Suppress warnings about missing serialVersionUID
@SuppressWarnings( "serial" ) public void myMethod1()

Note that @SuppressWarnings(value={"unchecked"}) is same as @SuppressWarnings("unchecked")

Assertion Exception

AnnotationTypeMismatchException
Its a runtime exception. Thrown to indicate that a program has attempted to access an element of an annotation whose type has changed after the annotation was compiled (or serialized).

IncompleteAnnotationException
Its a RuntimeException
Thrown to indicate that a program has attempted to access an element of an annotation type that was added to the annotation type definition after the annotation was compiled (or serialized). This exception will not be thrown if the new element has a default value.

Custom Annotation
From Structure point of view Annotations fall into three basic categories:

* Marker annotations have no variables. The annotation simply appears, identified by name, with no additional data supplied. For example, @MarkerAnnotation is a marker annotation. It includes no data, just the annotation name.
An annotation type with no elements is termed a marker annotation type, for example:

/**
* Indicates that the specification of the annotated API element
* is preliminary and subject to change.
*/
public @interface Preliminary { }

It is permissible to omit the parentheses in marker annotations, as shown below:

@Preliminary public class TimeTravel { ... }


* Single-value annotations are similar to markers, but provide a single piece of data. Because only a single bit of data is supplied, you can use a shortcut syntax (assuming the annotation type is defined to accept this syntax): @SingleValueAnnotation("my data"). This should look a lot like a normal Java method call, aside from the @ sign.

In annotations with a single element, the element should be named value, as shown below:

/**
* Associates a copyright notice with the annotated API element.
*/
public @interface Copyright {
String value();
}

It is permissible to omit the element name and equals sign (=) in a single-element annotation whose element name is value, as shown below:

@Copyright("2002 Yoyodyne Propulsion Systems")
public class OscillationOverthruster { ... }


* Full annotations have multiple data members. As a result, you must use a fuller syntax (and the annotation doesn't look quite so much like a normal Java method anymore):
 @FullAnnotation(var1="data value 1", var2="data value 2", var3="data value 3"). <


@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
String[] reviewers(); // Note use of array
}


The annotation type definition looks somewhat like an interface definition where the keyword interface is preceded by the @ character (@ = "AT" as in Annotation Type). The body of the annotation definition above contains annotation type element declarations, which look a lot like methods. Note that they may define optional default values.

// this code lives in a file called Copyright.java
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* embedded copyright
*/
@Documented
@Retention(RetentionPolicy.RUNTIME) @interface Copyright
{
// ------------------------------ FIELDS ------------------------------

/**
* copyright to embed via annotations so it is embedded in all classes that reference it
*/
String defaultCopyright =
"copyright (c) 1998-2008 Roedy Green, "
+ "Canadian Mind Products, http://mindprod.com";
// -------------------------- PUBLIC INSTANCE METHODS --------------------------
/**
* get value of this annotation
*
* @return the copyright string
*/
String value() default defaultCopyright;
}


Annotation Uses
In general, annotations benefits falls into three categories: documentation, compiler checking, and code analysis.
  • Documentation : is probably the least relevant reason for adding metadata to the Java language. Javadoc is very powerful.
  • Code Analysis :
  • Compiler Checking : like Override
Annotations allow programmers to decorate Java code with their own attributes. These attributes can be used for code documentation, code generation, and, even during runtime, for providing special services such as enhanced business-level security or special business logic.

Metadata provides a helpful way to indicate if methods are dependent on other methods, if they are incomplete, if a certain class must reference another class, and so on. This is indeed useful, but documentation is probably the least relevant reason for adding metadata to the Java language. Javadoc already provides a fairly easy-to-understand and robust way to document code. Besides, who wants to write a documentation tool when one already exists and works fine for the most part?

Many APIs require a fair amount of boilerplate code. For example, in order to write a JAX-RPC web service, you must provide a paired interface and implementation. This boilerplate could be generated automatically by a tool if the program were “decorated” with annotations indicating which methods were remotely accessible.

Other APIs require “side files” to be maintained in parallel with programs. For example JavaBeans requires a BeanInfo class to be maintained in parallel with a bean, and Enterprise JavaBeans (EJB) requires a deployment descriptor. It would be more convenient and less error-prone if the information in these side files were maintained as annotations in the program itself.

used to create documentation
used to track down dependencies in code
used to perform rudimentary compile-time checking.

The more advanced uses of annotations include writing an annotation processor that can read a Java program and take actions based on its annotations.






and should be run by the testing tool:

import java.lang.annotation.*;

/**
* Indicates that the annotated method is a test method.
* This annotation should be used only on parameterless static methods.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test { }

Note that the annotation type declaration is itself annotated. Such annotations are called meta-annotations. The first (@Retention(RetentionPolicy.RUNTIME)) indicates that annotations with this type are to be retained by the VM so they can be read reflectively at run-time. The second (@Target(ElementType.METHOD)) indicates that this annotation type can be used to annotate only method declarations.

Here is the testing tool:

import java.lang.reflect.*;

public class RunTests {
public static void main(String[] args) throws Exception {
int passed = 0, failed = 0;
for (Method m : Class.forName(args[0]).getMethods()) {
if (m.isAnnotationPresent(Test.class)) {
try {
m.invoke(null);
passed++;
} catch (Throwable ex) {
System.out.printf("Test %s failed: %s %n", m, ex.getCause());
failed++;
}
}
}
System.out.printf("Passed: %d, Failed %d%n", passed, failed);
}
}


References *
http://mindprod.com/jgloss/annotations.html
http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html
http://www.javaworld.com/javaworld/jw-07-2004/jw-0719-tiger3.html
http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html
http://www.ibm.com/developerworks/java/library/j-annotate1/index.html

No comments: