4

i'm working on my first annotation processor. I'm trying to get fields of class through annotation on declared object(that is a field of a method). For example:

public class Person {
    private String name;
    private String surname;
}

...
public void myMethod(@MyAnnotation Person person) { 
    /*...*/
}
...

Through @MyAnnotation i want to get 'name' and 'surname' fields.

Is that possible? I did something of similar with method's field:

...
for (Element element : roundEnvironment.getElementsAnnotatedWith(AnnotationOnMethod.class)) {
    ExecutableElement method = (ExecutableElement) element;
    List<? extends VariableElement> parameters = method.getParameters();
    parameters.forEach(p -> {
        /*code here for parameter*/
    });
}
...

Thanks in advance, Luca.

Solution: For my solution i am assuming that the annotation is on method and not on method's parameter. The correct answer to my question is the answer posted by rjeeb. You can see it below.


Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(AnnotationOnMethod.class);
for (Element element : elements) {
    ExecutableElement executableElement = (ExecutableElement) element; 
    List<? extends VariableElement> parameters = executableElement.getParameters();
    for (VariableElement parameter : parameters) {
        DeclaredType declaredType = (DeclaredType) parameter.asType();
        TypeElement clazz = (TypeElement) declaredType.asElement();
        clazz.getEnclosedElements().forEach(o -> {
                if (o.getKind().isField()) {
                    log.info("Simple name of field: " + o.getSimpleName());
                }
        });
    }
}

1 Answer 1

4

Your annotation is of type ElementType.PARAMETER so once you get the element that annotated with it then it should be TypeElement and therefore you can get the fields of this type element

for (Element element : roundEnv.getElementsAnnotatedWith(AnnotationOnMethod.class)) {
    TypeElement typeElement = elementUtils.getTypeElement(element.asType().toString());
    Set<? extends Element> fields = typeElement.getEnclosedElements()
            .stream()
            .filter(o -> o.getKind().isField())
            .collect(Collectors.toSet());

    // do something with the fields
}

you can get the helper classes from the AbstractProcessor

private Messager messager;
private Types typeUtils;
private Elements elementUtils;

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
    messager = processingEnv.getMessager();
    typeUtils = processingEnv.getTypeUtils();
    elementUtils = processingEnv.getElementUtils();
}
Sign up to request clarification or add additional context in comments.

5 Comments

Hi, thanks for the answer, can you tell me the package of "elementUtils" on you example? I cannot resolve it in my code. Anyway i resolved my problem, i will update this post :D
Thanks, your answer is really useful. I didn't know about that utilities. I will test your code to check if it works. If the code works i will accept the answer as solution. I edited this post, if you want let's check my solution :)
The only difference between my solution and yours is that you are assuming that the annotation will be in the method and not on method parameters
Yes, right. I just tested your code and it works like charm. Is good solution, thanks.
One word of caution: if your annotation processor is re-running incrementally, changes made to the Person class won't necessarily cause your processor to re-run, since your annotation is on the myMethod member, presumably in another class. Consider annotating the Person also so your annotation processor monitors changes there, or else advise your users that this may not work in gradle/eclipse/etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.