Intro to Java Annotations

This entry is part 9 of 13 in the series Intro to Java

Annotations allow you to attach metadata to a field, class, or method. Metadata is data that describes something else. For example, metadata about a song in mp3 format could be the artists name or the bit rate it was encoded at. A jpeg image could have metadata that described the image height or the number of colors in the image.

What do they look like?

@Override
public String getName() {
	return "no name";
}

The word after the ‘@’ is the Annotation. It precedes a method or class name. The Override annotation is built into Java. It is used to indicate that a method overrides a parents method. These are used for compiler hinds, for documentation, and to apply meta data.

Built in Annotations

  • @Deprecated : used much like the java doc comment
  • @Override ‚Äì indicates a method overrides a parents method
  • @SuppressWarnings ‚Äì tells compiler not to indicate warnings
  • @Documented ‚Äì tells javadoc to document the applied Annotations
  • @Retention(RetentionPolicy.xxx) ‚Äì indicate to compiler when the Annotation is available

Take a look at the Bird.getName() method, and the Animal.getType() method to see a couple of Annotations. Theese classes have been altered slightly here to add some annotations. AnnotationsTest1 shows what you will see in eclipse, or if you compile a deprecated method. AnnotationsTest2 shows how you can use @SupressWarnings.

public interface Animal {
   public void speak();
   public void move();
   public String getName();
   public void setName(String pName);
   /**
    * @ deprecated This will not work in the future
    */
   @Deprecated
   public String getType();
}
@Ratable(value=8)
public class Bird extends BaseAnimal {

   public Bird() {
      this(null);
   }

   public Bird(String pName) {
      super(pName);
      System.out.println("Bird created.");
   }

   @Ratable(6)
   public void move() {
      System.out.println(getDescription() + " is flying.");
   }

   @Ratable(10)
   public void speak() {
      System.out.println(getDescription() + " chirps.");
   }

   /**
    * Can't use @Override because it is an interface method
    */
   public String getType() {
      return "bird";
   }

   @Override
   public String getName() {
      return "no name";
   }
}
public class AnnotationsTest1 {
   public static void main(String[] args) {

      Fish aFish = new Fish();
      aFish.getType();

      Animal aAnimal = new Fish();
      // this line in Eclipse show a strike through on the method
      // when compiling with warnings you would get the error too
      aAnimal.getType();
   }
}
public class AnnotationsTest2 {

   public void doWithOutGenerics() {
      // without generics compiler gives warning about generic type
      List aList = new ArrayList();
      aList.clear();
   }

   @SuppressWarnings("unchecked")
   public void doWithAnnotations() {
      // adding annotation to remove compiler warning
      List aList = new ArrayList();
      aList.clear();
   }

   public void doWithGenerics() {
      // add type to List and ArrayList
      List aList = new ArrayList();
      aList.clear();
   }
}

Creating your own Annotations

If you would like to create your own Annotations, it is not very hard. For example look at the Ratable Annotation.

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Ratable {

   int value() default 0;

   int rating() default 1;

   String why() default "because";
}

The class is defined as an @Interface. This makes it an annotation. The strange method definitions that follow are the types of meta data that this annotation can contain. This one can have a value, a rating, and a why. One of the neat things, is that you can provide defaults in the case that someone using your annotation does not provide values for them. So how would you apply this annotation?

Look at the first couple of lines from Fish.

@Ratable(rating = 2, why = "Smells Bad")
public class Fish extends BaseAnimal {

The Ratable annotation has been applied to the class Fish with a rating of 2, a value of 0 (default) and a why of “Smells Bad”.

Why would you want your own Annotations?

Why would create your own? If you create an annotation, you can use them with compiler tools to provide information. If you specify a RetentionPolicy of Runtime, then you can use your annotation at Runtime. What good would that be? Think about MP3 files. You can do a search of all your music for all music files that are by a certain author. You can do that with annotations of your classes as well. You can use annotations instead of using instanceof. You can also scan the class path to look for annotations.

Several well know packages and utilities have started to use annotations for configuration. Struts2, JBoss, and hibernate are some you may have heard about. This idea allows you to specify configuration right in the classes themselves instead of in separate XML or properties files.

The Java reflections API provides some help for dealing with these as runtime, but libraries have been created that help with this. One such library is also called “reflections”. AnnotationsTest3 is an example that uses this API.

public class AnnotationsTest3 {
   public static void main(String[] args) {
      AbstractConfiguration configuration = new AbstractConfiguration(); 

      configuration.setUrls(ClasspathHelper.getUrlsForCurrentClasspath());
      configuration.setScanners(new ClassAnnotationsScanner());
      configuration.setFilter(new IncludePrefix("net.cyberward.tutorial.java.annotations"));

      Reflections reflections = new Reflections(configuration);
      Set> annotated = reflections.getTypesAnnotatedWith(Ratable.class);

      for (Class aAnnotatedClass : annotated) {
         Ratable aRateableAnnotation = aAnnotatedClass.getAnnotation(Ratable.class);
         System.out.println(aAnnotatedClass);
         System.out.println(aRateableAnnotation);
         System.out.println("rateing:"+aRateableAnnotation.rating());
         System.out.println();
      }
   }
}

More Information:

Note: If you are using Eclipse and do a “Refactor / Rename…” of an Annotation, all the places that use the Annotation will be modified too.

Series NavigationIntro to Java GenericsIntro to Java Patterns