Understanding Compile time processing using annotation processor

Different ways to understand Compile time processing using annotation processor

1. Using the @Setter annotation means a marker can be applied to methods.
The annotation will no doubt be discarded during compilation not be available after compilation.

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

    @Retention(RetentionPolicy.SOURCE)
    @Target(ElementType.METHOD)
    public @interface Setter {
    }

The annotation processor

The SetterProcessor class is used by the compiler to process the annotations.
It checks, if the methods annotated with the @Setter annotation are
non-static methods with a name starting with set and having a uppercase letter
as 4th letter. If one of these conditions isn’t met, a error is written to the Messager.
The compiler writes this to stderr, but other tools could use this information differently.

 

    package annotation.processor;

        import annotation.Setter;
        import java.util.Set;
        import javax.annotation.processing.*;
        import javax.lang.model.*;
        import javax.lang.model.element.*;
        import javax.tools.Diagnostic;

@SupportedAnnotationTypes({"annotation.Setter"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SetterProcessor extends AbstractProcessor {

    private Messager messager;

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// get elements annotated with the @Setter annotation
        Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Setter.class);

        for (Element element : annotatedElements) {
            if (element.getKind() == ElementKind.METHOD) {
// only handle methods as targets
                checkMethod((ExecutableElement) element);
            }
        }

// don't claim annotations to allow other processors to process them
        return false;
    }

    private void checkMethod(ExecutableElement method) {
// check for valid name
        String name = method.getSimpleName().toString();
        if (!name.startsWith("set")) {
            printError(method, "setter name must start with \"set\"");
        } else if (name.length() == 3) {
            printError(method, "the method name must contain more than just \"set\"");
        } else if (Character.isLowerCase(name.charAt(3))) {
            if (method.getParameters().size() != 1) {
                printError(method, "character following \"set\" must be upper case");
            }
        }

// check, if setter is public
        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
            printError(method, "setter must be public");
        }

// check, if method is static
        if (method.getModifiers().contains(Modifier.STATIC)) {
            printError(method, "setter must not be static");
        }
    }

    private void printError(Element element, String message) {
        messager.printMessage(Diagnostic.Kind.ERROR, message, element);
    }

    @Override
    public void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

// get messager for printing errors
        messager = processingEnvironment.getMessager();
    }

}

2. Packaging

The are mostlyt used when the annotation processor needs to be made available to the SPI.

To acheive this To do this ,a text file META-INF/services/javax.annotation.processing.Processor
needs to be added to the jar file containing the annotation processor and
the annotation in addition to the other files. The file needs to include the fully
qualified name of the annotation processor, i.e. it should look like this

annotation.processor.SetterProcessor
Suppose the jar file is named Developer.jar
This class below is in the default package with the annotations being applied to the
correct elements according to the retention policy.

import annotation.Setter;

    public class Behaviour {

        @Setter
        private void setValue(String value) {}

        @Setter
        public void setString(String value) {}

        @Setter
        public static void main(String[] args) {}

    }

Using the annotation processor with javac

If the annotation processor is discovered using the SPI, it is automatically used to process annotated elements. E.g. compiling the AnnotationProcessorTest class using

javac -cp Developer.jar Behaviour.java
yields the following output

Behaviour.java:6: error: setter must be public private void setValue(String value) {}
^
Behaviour.java:12: error: setter name must start with “set” public static void main(String[] args) {}
^
2 errors instead of compiling normally. No .class file is created.

This could be prevented by specifying the -proc:none option for javac.
Hope you enjoy this ? Look out for more intereting articles

Advertisements

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

Blog at WordPress.com.

Up ↑

%d bloggers like this: