Annotation Processors

Lambdas are very popular now. But I realized I haven’t used the annotation processor API since JSE 5. None of the projects I came across has even used good generics. So even JSE 5 is not properly used.

I just compiled and executed this. It is not complete because I am trying to print all the annotations actually used in the code shown(Test.java) in my previous blog entry.

I am using

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)

Now it is printing this.

Annotation [com.test.Test.TypeUse] [[com.test.Test.Test1]]
Annotation [com.test.Test.TypeParameter] [[T, S]]
Annotation [com.test.Test.TestTypeParameter] [[T, S]]
Annotation [@com.test.Test.TypeUse] [com.test.Test.Test1]
Annotation [] [java.lang.Integer]
Annotation [@com.test.Test.NonNull] [argv]

I will update the code later once I manage to fix it.

Update : Now it is printing this. Code is updated. I will explain the changes.

Annotation [com.test.Test.TypeParameter] [[T, S]]
Annotation [com.test.Test.TestTypeParameter] [[T, S]]
Annotation [@com.test.TypeUse] [com.test.Test.Test1]
Annotation [[Lcom.test.TypeUse;@2a5ca609] [java.lang.Integer]
Annotation [@com.test.Test.NonNull] [argv]
-> (java.lang.String[])void

Change 1

This method which I used earlier turns the TypeMirror back to a DeclaredType. That is not required.

    private void processClassTypeParameters(Element e) {
        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {
            //System.out.println( "Annotation [" + typeParameterElement.getAnnotationMirrors() + "] [" + typeParameterElement  + "]");
            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {
                System.out.println( "Annotation [" + ((DeclaredType)typeMirror).getAnnotationMirrors() + "] [" + typeMirror  + "]");
            }
        }
    }

This method is replaced with the new method in Test.java shown below. typeMirror.getAnnotationsByType(TypeUse.class) is sufficient to get the annotation on Integer

Change 2

I introduced a new method to get the annotations inside a method and source on which they are applied. But that is not possible. Alex Buckley, the JSR 308 spec. lead replied that

There is no access to annotations in a method body from the Language Model API (or the Core Reflection API).

Actually I introduced this method and called it like this e.asType().accept(visitor(),null); to try to get the annotations from inside the method. This is the method that is printing

    -> (java.lang.String[])void

    private TypeVisitor<Boolean, Void> visitor() {
        return new SimpleTypeVisitor<Boolean, Void>() {
            public Boolean visitExecutable(ExecutableType t, Void v) {
                System.out.println("-> " + t);
                return true;
            }
        };
    }


AnnotationFinder.java

package com.test;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleTypeVisitor6;
import javax.lang.model.util.SimpleTypeVisitor8;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static javax.lang.model.util.ElementFilter.typesIn;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class AnnotationFinder extends AbstractProcessor{


    public AnnotationFinder(){
        super();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        TypeElement tye = null;

        if( !roundEnv.processingOver()){

            Iterator<? extends Element> te = annotations.iterator();

            for (TypeElement element : typesIn(roundEnv.getRootElements()) ) {

                processEnclosedElements(element.getEnclosedElements(),
                                        roundEnv);

            }
        }
        return false;
    }

    private void processEnclosedElements(List<? extends Element> enclosedElements,
                                         RoundEnvironment roundEnv) {

        for( Element e : enclosedElements ){

            if( e.getKind() == ElementKind.ANNOTATION_TYPE &&

                    !roundEnv.getElementsAnnotatedWith((TypeElement) e).isEmpty()){

                System.out.println( "Annotation [" + e + "] [" +
                        roundEnv.getElementsAnnotatedWith((TypeElement) e) + "]");

            }else if( e.getKind() == ElementKind.METHOD ){

                for (VariableElement variableElement : ((ExecutableElement) e).getParameters()) {

                    System.out.println("Annotation [" + variableElement.getAnnotationMirrors() + "] [" +

                                                                                         variableElement + "]");
                    e.asType().accept(visitor(),null);

                }

            }else if (e.getKind() == ElementKind.CLASS){

                System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e  + "]");

                processClassTypeParameters(e);
            }
        }
    }

    private TypeVisitor<Boolean, Void> visitor() {

        return new SimpleTypeVisitor8<Boolean, Void>() {

            public Boolean visitExecutable(ExecutableType t, Void v) {

                System.out.println("-> " + t);

                return true;
            }
        };
    }

    private void processClassTypeParameters(Element e) {

        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {

            //System.out.println( "Annotation [" + typeParameterElement.getAnnotationMirrors() + "] [" + typeParameterElement  + "]");

            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {

                System.out.println( "Annotation [" + typeMirror.getAnnotationsByType(Test.TypeUse.class) + "] [" + typeMirror  + "]");

            }
        }
    }
}

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

%d bloggers like this: