How can I refer to implementations of a method in annotation processing?

谁说胖子不能爱 提交于 2020-01-12 06:26:10

问题


I am playing around with Java (javax) annotation processing.

Suppose I have an annotation for methods:

@Target(ElementType.METHOD)
public @interface MethodAnnotation { }

Now I want to process all the methods which are overridden from a type with the annotated method:

interface MyInterface() {
    @MethodAnnotation
    void f()
}

class MyClass implements MyInterface {
    override void f() { } // <- I want to process this method
}

@Inherited meta-annotation seems not to be suitable here:

Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class.

Also, is it possible to process an inherited class method which is not overridden in a subclass? Like this:

class MyClass {
    @MethodAnnotation
    void f() { }
}

class MySubClass extends MyClass { } // <- I want to process its f()
                                     //    or at least to find out that it doesn't
                                     //    override the method

How can I access the overriden methods of a certain method within AbstractProcessor?

I guess, to achieve this I need to find subclasses of the eclosing class, but I haven't found a way to do this either.

UPD: I suppose it's possible using RoundEnvironment.getRootElements() but still found no proper way of doing this.


回答1:


The short answer is that out-of-the-box annotation processing isn't going to make this easy for you, but it can be done.

Rather than using the normal dispatch mechanism for processing, you're actually going to have to process every method and do the filtering yourself.

Step 1:

Define your processor so that it supports all annotations by using "*" as its supported annotation type. This will mean that your processor will get invoked every round.

Step 2:

Use getRootElements to get the entire set of elements every round.

Step 3:

Create an ElementScanner8 to traverse any element that you find to look for ExecutableElements. If you're willing to trust that overridden methods are annotated with @Override, you can do a quick filter on those. Otherwise, just look at all of them.

Step 4:

Now you need to see if the method overrides a method with the annotation you're looking for. There's no easy way to get methods that a given method has overridden, so you need to get the enclosing element of the method, look at its superclass and implemented interfaces (recursively), get their enclosed elements, filter out the methods, and test to see if it has been overridden by the method in question. If it has, you can check the annotations to see if it has one you care about.

Step 5:

At this point, you should have the overriding method, the overridden method and the annotation mirror that you were looking for, so you should be able to implement whatever logic you wanted.




回答2:


If those annotations are available at runtime, and you want to reach them at runtime, you can use the Reflections library.

For example:

Collection<URL> urls = ClasspathHelper.forPackage("nl.shopname.location.domain");

Reflections reflections = new Reflections(
    new ConfigurationBuilder().setUrls(urls).setScanners(new FieldAnnotationsScanner()));

Set<Field> fieldsWithAnnotation = reflections.getFieldsAnnotatedWith(MyAnnotation.class); 



回答3:


according to the javadoc of javax.annotation.processing.Processor in Jsr269-1.8

An annotation is present if it meets the definition of being present given in AnnotatedConstruct. In brief, an annotation is considered present for the purposes of discovery if it is directly present or present via inheritance. An annotation is not considered present by virtue of being wrapped by a container annotation...

The JavaDoc of AnnotatedConstruct#getAnnotationsByType says that it returns indirectly present annotations, so I think you should scan for methods and check if they indirectly have the annotation using this call. Something in the spirit of this.

Disclaimer... haven't tried it ;)




回答4:


Method annotations are not inherited. Type annotations can be inherited through the use of "@Inherited" annotation.

What you could do is define a functional interface with an inherited type annotation, however I don't know if this is elegant enough for you.



来源:https://stackoverflow.com/questions/38292131/how-can-i-refer-to-implementations-of-a-method-in-annotation-processing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!