Annotation Processors
December 13, 2013 Leave a comment
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 + "]"); } } } }