Alexis Dufrenoy
Alexis Dufrenoy

Reputation: 11966

How to get the type of a field in an annotation processor?

I'm trying to write an annotation to check if an object is immutable at runtime. In order to do so, I check if the class of the object is final and then if all its attributes are also final. And then, I want to check the same thing recursively for the type of each field if it's not a primitive type.

Here a piece of code:

for (Element subElement : element.getEnclosedElements()) {
    if (subElement.getKind().isField()) {
        isFinal=false;

        for(Modifier modifier : subElement.getModifiers()) {
            if (modifier.equals(Modifier.FINAL)) {
                isFinal=true;
                break;
            }
        }
        if (!isFinal) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Field "+element+" is not immutable because it is not final");
        } else {
            // Here I want to restart my method recursively
        }
    }
}

How can I get my method to start all over again with the type of my field? How can I retrieve the type of the field, which is here a javax.lang.model.element.Element?

Edit: I need the type as declared in the containing class, which needs to be a final class to avoid any kind of mutability.

Upvotes: 3

Views: 3096

Answers (3)

Noman
Noman

Reputation: 303

I think

String type = element.asType().toString();

also gets the fully qualified name of the type of the fields.

Upvotes: 3

Hendra Anggrian
Hendra Anggrian

Reputation: 5858

I've been able to do it with Square's javapoet ClassName class:

Element element = ...
ClassName className = ClassName.get(element.asType());
String name = className.toString();

If, for example, the annotated field is a String, it will return Java.lang.String. I'm open to a better solution than this one.

Upvotes: 2

MvG
MvG

Reputation: 61057

I never have needed javax.lang.model before. If you intend to check things at runtime, I'd go through java.lang.Class and java.lang.reflect.Field instead. There you can use getTypeto obtain the type of the field. You can also have a look at all fields, including inherited ones, using getFields. Or you can look at ancestor classes and their declared fields, to get at private ones as well.

Edit: the following consideration appears to be no longer relevant

Notice that even that type information will return the declared type, i.e. the type as it is written in the source code. The field might still hold a reference to a derived class at runtime. Possible counter-measures would be having all those classes declared final, so that there can be no derived classes, or tracing all assignments to those fields, which would mean major static data flow analysis. Not sure that's worth the effort.

Upvotes: 0

Related Questions