JMU
Compile-Time Processing of Annotations
in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Review
Compile-Time Processing
Compile-Time Processing (cont.)
An Example
An Example (cont.)

The Annotation

javaexamples/annotations/FinalAttributes.java
import java.lang.annotation.*;

/**
 * An annotation that can be used to indicate that a class
 * must have final attributes.
 * 
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
@Target(ElementType.TYPE)          // The annotation can be used anywhere a type is used
@Retention(RetentionPolicy.CLASS)  // Retained at compile-time; ignored at run-time
public @interface FinalAttributes 
{
  // No annotation type elements
}
        
An Example (cont.)

The Processor

javaexamples/annotations/FinalProcessor.java
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.tools.*;

/**
 * An annotation processor that identifies attributes that
 * in a class that should be but aren't declared final.
 * 
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
@SupportedAnnotationTypes("FinalAttributes")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class FinalProcessor extends AbstractProcessor 
{
  private Messager messager;
  
  /**
   * Initialize this Processor.
   * 
   * @param env  The ProcessingEnvironment to use
   */
  @Override
  public void init(final ProcessingEnvironment env)
  {
    messager = env.getMessager();
  }
  
  /**
   * Process a Set of annotations.
   * 
   * @param annotations The Set of TypeElement objects (i.e., the annotated elements)
   * @param roundEnv  The RoundEnvironment to use
   */
  @Override
  public boolean process(final Set< ? extends TypeElement > annotations, final RoundEnvironment roundEnv) 
  {
    for(final Element element: roundEnv.getElementsAnnotatedWith(FinalAttributes.class)) 
    {
      if(element instanceof TypeElement) 
      {
        final TypeElement typeElement = (TypeElement)element;

        for( final Element enclosedElement: typeElement.getEnclosedElements()) 
        {
          if(enclosedElement instanceof VariableElement) 
          {
            final VariableElement variableElement = (VariableElement)enclosedElement;

            if( !variableElement.getModifiers().contains(Modifier.FINAL) ) 
            {
              messager.printMessage(Diagnostic.Kind.ERROR,
                  String.format("Attribute %s must be declared final",variableElement.getSimpleName()),
                  variableElement);           
            }
          }
        }
      }
    }
    return true; // To indicate that the annotations have been processed
  }
}
        
An Example (cont.)

Using the Annotation

@FinalAttributes
public class Student 
{
  private int    id;
  private String name;
  
  public Student(String name)
  {
    this.name = name;
    this.id = IDGenerator.generate();
  }
  
  public String getID()
  {
    return name;
  }
  
  public String getName()
  {
    return name;
  }
}