Johnyb
Johnyb

Reputation: 1316

Get type of variable in annotation processor

I have annotation processor. I retrieve the list of variables of the class that was annotated with my annotation this way:

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    for (TypeElement annotation : annotations) {
        Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
        for (Element el : annotatedElements) {
            try {
                generate(el);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return true;
}

private void generate(Element annotatedElement) throws IOException {
        TypeElement targetClass = (TypeElement) annotatedElement;
        List<? extends Element> enclosedElements = targetClass.getEnclosedElements();
        List<VariableElement> fields = new ArrayList<>(enclosedElements.size());
        for (Element field : enclosedElements) {
            if (field.getKind() == ElementKind.FIELD && !field.getModifiers().contains(Modifier.STATIC)) {
                fields.add((VariableElement) field);
            }
        }
       processFields(fields);
}

Now fields List contains list of all variables. But i need to extract the TYPE of variables, so for example if class has private String blabla i want to getString

I am doing it following way:

void processFields(List<VariableElement> elements){
    List<String> types =elements
    .stream()
    .map( e -> e.asType().toString())
    .collect(Collectors.toList());        
}

List types now contains all types of variables. However, if i have class like this

@MyAnnotation
public class Test{
  @NotBlank(message = "message")
  private String name;
}

The type of the variable name is not string, its (@javax.validation.constraints.NotBlank(message="message") :: java.lang.String

How can i get just type without annotations then? Is there any way?

Thanks for help!

Upvotes: 1

Views: 911

Answers (1)

Allen D. Ball
Allen D. Ball

Reputation: 2026

Add members and override init() to get the instances of Elements and Types.

...
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
...
    /** See {@link javax.annotation.processing.ProcessingEnvironment#getElementUtils()}. */
    protected Elements elements = null;
    /** See {@link javax.annotation.processing.ProcessingEnvironment#getTypeUtils()}. */
    protected Types types = null;
...
    @Override
    public void init(ProcessingEnvironment processingEnv) {
        elements = processingEnv.getElementUtils();
        types = processingEnv.getTypeUtils();
    }
...

FYI, you can simplify your generate(Element) method:

...
import javax.lang.model.util.ElementFilter;
...
private void generate(Element annotatedElement) throws IOException {
    List<VariableElement> fields =
        ElementFilter.fieldsIn(Collections.singleton(annotatedElement)).stream()
        .filter(t -> (! t.getModifiers().contains(Modifier.STATIC)))
        .collect(Collectors.toList());

    processFields(fields);
}

Your processFields(List<VariableElement>) method could look something like below. I made all the steps explicit but you can look at TypeElement and Name methods to determine which String you want.

void processFields(List<VariableElement> in) {
    List<String> out =
        in.stream()
        .map(e -> e.asType())           /* javax.lang.model.type.TypeMirror */
        .map(e -> types.asElement(e))   /* javax.lang.model.element.Element */
        .map(e -> (TypeElement) e)      /* javax.lang.model.element.TypeElement */
        .map(e -> e.getQualifiedName()) /* javax.lang.model.element.Name */
        .map(e -> e.toString())
        .collect(Collectors.toList());
}

Upvotes: 2

Related Questions