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; } }