Search code examples
javaandroidannotation-processingannotation-processor

Get enclosing class name of a VariableElement in javax.annotation.processing.Processor


I am just starting to learn annotation processing in Java. I have @MyAnnotation which targets ElementType.FIELD, In my Processor I am limiting the annotation to only allow non-null unique value. Which is working as it should.

While logging errors in case where there is infact some duplicate value set to MyAnnotation.value, I want to provide the complete path of both the existing annotations in the source code and the new duplicate one.

My Annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface   ProviderColumn {
    String content_id();
}

Example Parent Class.

public class EnclosingParent {
    @ProviderColumn(content_id="Hello")
    private String value1;

    @ProviderColumn(content_id="Hello")
    private String value2;
}

My AnnotationProcessor

@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)
{
    UniqueColumnNameChecker columnNameChecker = new UniqueColumnNameChecker();

    try {

        for (Element annotatedElement : roundEnvironment.getElementsAnnotatedWith(ProviderColumn.class)) {

            // We can cast it, because we know that it is of ElementType.FIELD
            VariableElement variableElement = (VariableElement) annotatedElement;

            try {
                ProviderColumnId providerColumnId =
                        new ProviderColumnId(variableElement);

                // How can I get the EnclosingParent.class or even just a complete canonical class name?

                // throws a DuplicateAnnotationIdException when it detects duplicate entries.
                columnNameChecker.addAnnotationColumnName(providerColumnId);
            }
            catch (IllegalArgumentException e) {
                error(variableElement, e.getMessage());
                return true;
            }
        }
    }
    catch (DuplicateAnnotationIdException ex) {
        error(ex.getMessage());
        return true;
    }

    return true;
}

However I am having trouble figuring out how to obtain enclosing class information from a VariableElement. Since I'm only starting on AnnotationProcessing I'm not even sure if this is possible and I haven't been able to find any questions related to this issue on StackOverflow or anywhere else.

Expected error output

Duplicate content_id()='Hello' detected, Found at 'com.example.EnclosingParent.value1' and 'com.example.EnclosingParent.value2'.

Note: I realize I can get parent info if I define a new ElementType.TYPE Annotation and set to the Enclosing class, but I'm looking to avoid that as it adds additional responsibilities for the third party developer.


Solution

  • Stupid question apparently. I was looking in all the wrong places for the enclosing element, found this excellent Annotation Processor Tutorial which states:

    Elements and TypeMirrors

    ...

    You can think of it like a XML file you try to parse (or an abstract syntax tree in compiler construction)

    And I realized the Element itself might contain all the information I need.

    Just need to call variableElement.getEnclosingElement() to get the parent Element

    From there on it was easy, you can get enclosing class name like so:

    element.getEnclosingElement().asType().toString();
    

    This however doesn't guarantee the enclosing element to be of TypeElement. So just use instanceof to ensure that it is.