|
Compile-Time Processing of Annotations
in Java |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
Processor classesjavac command has a -processor
option that allows you to specify a Processor
Processor
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
}
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
}
}
@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;
}
}