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 + "]");
}
}
}
}