简体   繁体   中英

Java annotation - how to get properties and class in processor

For the following custom Java annotation

@CustomAnnotation(clazz=SomeClass.class)
public class MyApplicationCode
{ 
   ... 
}

I basically want to be able to grab both the Class object for the MyApplicationCode and the clazz parameter at compile time to confirm some coding convention consistencies (another story). Basically I want to be able to access MyApplicationCode.class and Someclass.class code in the annotation processor. I'm almost there but I'm missing something. I have

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface CustomAnnotation
{
   public Class clazz();
}

Then I have for the processor:

public class CustomAnnotationProcessor extends AbstractProcessor
{
    private ProcessingEnvironment processingEnvironment;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment)
    {
        this.processingEnvironment = processingEnvironment;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment)    
    {
        Set<? extends Element> elements = environment.getElementsAnnotatedWith(ActionCommand.class);

        for(Element e : elements)
        {
            Annotation annotation = e.getAnnotation(CustomAnnotation.class);
            Class clazz = ((CustomAnnotation)annotation).clazz();        

            // How do I get the actual CustomAnnotation clazz?
            // When I try to do clazz.getName() I get the following ERROR:
            // Attempt to access Class object for TypeMirror SomeClass

            // Also, how do I get the Class object for the class that has the annotation within it?
            // In other words, how do I get MyApplicationCode.class?
        }
    }
}

So what I'm trying to do in the process method is to grab SomeClass.class and MyApplication.class from the original code below to do some custom validation at compile time. I can't seem for the life of me figure out how to get those two values...

@CustomAnnotation(clazz=SomeClass.class)
public class MyApplicationCode

Update: The following post has a lot more details, and it's much closer. But the problem is that you still end up with a TypeMirror object from which to pull the class object from, which it doesn't explain: http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/

Update2: You can get MyApplication.class by doing

String classname = ((TypeElement)e).getQualifiedName().toString();

I was going to point you in the direction of the blog http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/ , but it looks like you already found that one.

I see you figured out how to access the MyApplication Element, so I wont cover that....

The exception you see actually contains the type of the annotation property within it. So you can reference the annotation clazz value when you catch the exception:

public class CustomAnnotationProcessor extends AbstractProcessor
{
    private ProcessingEnvironment processingEnvironment;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment)
    {
        this.processingEnvironment = processingEnvironment;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment)    
    {
        Set<? extends Element> elements = environment.getElementsAnnotatedWith(ActionCommand.class);

        for(Element e : elements)
        {
            CustomAnnotation annotation = e.getAnnotation(CustomAnnotation.class);    

            TypeMirror clazzType = null;
            try {
                annotation.clazz();
            } catch (MirroredTypeException mte) {
                clazzType = mte.getTypeMirror();
            }

            System.out.println(clazzType); // should print out SomeClass

        }
    }
}

Yes, this is a total hack of a solution, and I'm not sure why the API developers decided to go this direction with the annotation processor feature. However, I have seen a number of people implement this (including myself ), and the article mentioned describes this technique as well. This seems to be an acceptable solution at the moment.

In terms of "grabbing" the class values for MyApplicationCode and SomeClass, you will not be able to do so if they are classes being compiled. You can, however, use the Element and TypeMirror representations to perform some high level validation on your classes (Method, Field, Class names, annotations present, etc)

After reading this related SO question , I found this excellent page about the Java Annotation Processing Tool (APT) . It's from 2005 so may not be the best way to do this these days.

APT [...] is an annotation processing tool for Java. More specificially, APT allows you to plug code in to handle annotations in a source file as the code compilation is occurring - and in that process, you can emit notes, warnings, and errors.

This is only for Oracle's JDK.

It is compile time. I would think the compiler is not even finished up compiling the source code. You retrieve such information from AnnotatedElement instance which will give you relevant information of the type you have annotated, but not its runtime properties, thats not yet available since the relevant class files are not yet loaded by the virtual machine. And the compiler is not even guaranteed to be running under a virtual machine for java, so it is not mandated to be able to load class files. Its requirement is only to be able to produce bytecodes that any particular virtual machine can read.

So go check on the mirror Api, and for any relevant information on the class/method/field you have annotated, check on AnnotatedElement representing that instance.

And as aside note: this is information is just what i reasoned up, so it might not be the actual truth.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM