jump to navigation

Annotations August 12, 2005

Posted by Coolguy in J2SE.
trackback
  • One of the latest trends in programming, particularly in Java programming, is the use of metadata
  • Metadata, simply put, is data about data
  • Metadata can be used to create documentation, to track down dependencies in code, and even to perform rudimentary compile-time checking
  • A rash of tools for metadata, such as XDoclet add these features to the core Java language and have been part of the Java programming landscape for a while.
  • Until the availability of J2SE 5.0 the core Java language came closest to a metadata facility with the Javadoc methodology.
  • You use a special set of tags to mark up your code and then execute the javadoc command to turn the tags into a formatted HTML page that documents the classes the tags are attached to
  • Tiger incorporates a far more versatile metadata facility into the core Java language through a new feature called annotations
  • Annotations are modifiers you can add to your code and apply to package declarations, type declarations, constructors, methods, fields, parameters, and variables.
  • Tiger includes built-in annotations and also supports custom annotations you can write yourself.

Value of metadata

  • In general, metadata’s benefits fall into three categories:
  • Documentation
  • Compiler checking
  • Code analysis
  • Code-level documentation is the most-often-cited use.
  • 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.
  • A more significant advantage of metadata is the ability for a compiler to use it to perform some basic compile-time checking.
  • Tiger introduces an annotation that lets you specify that a method overrides another method from a superclass.
  • The Java compiler can ensure that the behavior you indicate in your metadata actually happens at a code level.
  • Most Java programming veterans have spent at least a few long nights trying to discover why their code doesn’t work. When you finally realize that a method has a parameter wrong, and in fact isn’t overriding a method from a superclass, much bitterness can result. A tool that consumes metadata can help you discover this type of error easily and save those nights
  • Arguably, the nicest feature of any good annotation or metadata tool is the ability to use the extra data to analyze code.In a simple case, you might build up a code catalog, provide required input types, and indicate return types.

Annotation basics

  • Annotations take the form of an “at” sign (@), followed by the annotation name.
  • Then, you supply data to the annotation — when data is required — in name=value pairs
  • Annotations fall into three basic categories
  • Marker annotations: They 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.
  • Single-value annotations : They 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 : @SingleValueAnnotation(“my data”). This should look a lot like a normal Java method call, aside from the @ sign.
  • Full annotations : They have have multiple data members. As a result, you must use a fuller syntax : @FullAnnotation(var1=”data value 1″, var2=”data value 2″, var3=”data value 3″).
  • You can also supply arrays of values to annotation variables, through curly braces.
    Using arrayed values in annotations


    @TODOItems({ // Curly braces indicate an array of values is being supplied
    @TODO(
    severity=TODO.CRITICAL,
    item="Add functionality to calculate the mean of the student's grades",
    assignedTo="Brett McLaughlin"),
    @TODO(
    severity=TODO.IMPOTANT,
    item="Print usage message to screen if no command-line flags specified",
    assignedTo="Brett McLaughlin"),
    @TODO(
    severity=TODO.LOW,
    item="Roll a new website page with this class's new features",
    assignedTo="Jason Hunter")
    }
    )

The Override annotation

  • Tiger’s first built-in annotation type is Override
  • Override should be used only on methods (not on classes, package declarations, or other constructs).
  • It indicates that the annotated method is overriding a method in a superclass.
package com.oreilly.tiger.ch06;
public class OverrideTester {
public OverrideTester() { }

@Override
public String toString() {
return super.toString() + " [Override Tester Implementation]";  }


@Override
public int hashCode() {
return toString().hashCode();  
}
}
  • The @Override annotation annotates two methods -- toString() and hashCode() -- to indicate that they override versions of the methods from the OverrideTester class's superclass (java.lang.Object).
  • You cannot compile this class without overriding these methods.
package com.oreilly.tiger.ch06;
public class OverrideTester {
public OverrideTester() { }
@Override 
public String toString() {
return super.toString() + " [Override Tester Implementation]";
}
@Override
public int hasCode() {
return toString().hashCode();
}
}
  • In the above Listing , hashCode() is mistyped as hasCode(). The annotation indicates that hasCode() should override a method. But in compilation, javac will realize that the superclass (again, java.lang.Object) has no method named hasCode() to override. As a result, the compiler gives you an error

The Deprecated annotation

  • Like Override, Deprecated is a marker annotation.
  • You use Deprecated to annotate a method that shouldn't be used anymore.
  • Unlike Override, Deprecated should be placed on the same line as the method being deprecated


  • package com.oreilly.tiger.ch06;
    public class DeprecatedClass {
    @Deprecated public void doSomething(){
    // some code
    }
    public void doSomethingElse(){
    // This method presumably does what doSomething() does, but better
    }
    }

  • If you then use the deprecated method, either by overriding it or invoking it, the compiler processes the annotation, realizes that the method shouldn't be used, and issues an error message

The SuppressWarnings annotation

  • The last annotation type that you get "for free" with Tiger is SuppressWarnings
  • SupressWarnings comes to the rescue. SupressWarnings, unlike Override and Deprecated, does have a variable
public void nonGenericsMethod() {
List wordList = new ArrayList(); // no typing information on the List
wordList.add("foo"); // causes error on list addition}
  • Code above causes a unchecked warning from complier
  • To suppress the warning:
@SuppressWarnings(value={"unchecked"})
public void nonGenericsMethod() {
List wordList = new ArrayList(); // no typing information on the List
wordList.add("foo"); // causes error on list addition
}

Defining your own annotation type

  • Defining a new annotation type is a lot like creating an interface, except that you precede the interface keyword with the @ sign.

package com.oreilly.tiger.ch06;
/*** Marker annotation to indicate that a method or class
* is still in progress.
*/
public @interface InProgress { }

  • If you compile this annotation type and ensure that it's in your classpath, you can then use it on your own source code methods to indicate that a method or class is still in progress
@com.oreilly.tiger.ch06.InProgress
public void calculateInterest(float amount, float rate) 
{// Need to finish this method later
}

Adding a member

package com.oreilly.tiger.ch06;
/*** Annotation type to indicate a task still needs to be
* completed.
*/
public @interface TODO {
String value();
}
@com.oreilly.tiger.ch06.InProgress
@TODO(value="Figure out the amount of interest per month")
public void calculateInterest(float amount, float rate) 
{// Need to finish this method later
}

Setting default values

package com.oreilly.tiger.ch06;public 
@interface GroupTODO {
public enum Severity { CRITICAL, IMPORTANT, TRIVIAL, DOCUMENTATION };
Severity severity() default Severity.IMPORTANT;
String item();
String assignedTo();
String dateAssigned();
}

@com.oreilly.tiger.ch06.InProgress
@GroupTODO(
item="Figure out the amount of interest per month",
assignedTo="Brett McLaughlin",
dateAssigned="08/04/2004")
public void calculateInterest(float amount, float rate) {
// Need to finish this method later
}

More

http://www-128.ibm.com/developerworks/library/j-annotate2.html

Advertisements

Comments»

No comments yet — be the first.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: