Getelementsannotatedwith метод возвращает пустой список при обработке аннотации

Моя цель - генерация кода с помощью процессора аннотаций. Я хочу создать новый класс поверх существующего базового класса, исключив некоторые поля в соответствии с аннотациями и добавив некоторые валидаторы constarint и т. д. У меня есть 3 модуля. Первый - это базовый модуль, который содержит класс Car и аннотации BaseClass, A и B. Второй модуль - это модуль процессора аннотаций. Он содержит аннотацию CustomCodeGenerator и ее обработчик. И третий модуль - это модуль, который я хочу создать для него класс NewCar и использовать в нем этот класс NewCar.

Автомобиль.Класс

@BaseClass
public class Car {

    @A
    private int seatCount;

    @B
    private String name;

    private String dummy;

    public Car(int seatCount, String name) {
        this.seatCount = seatCount;
        this.name = name;
    }

    public int getSeatCount() {

        return seatCount;
    }

    public void setSeatCount(int seatCount) {

        this.seatCount = seatCount;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
   }

    public String getDummy() {
    return dummy;
    }

    public void setDummy(String dummy) {
        this.dummy = dummy;
    }
}

CustomCodeGenerator.class

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface CustomCodeGenerator {
}

CustomCodeGeneratorProcessor.class

import com.squareup.javapoet.*;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.io.IOException;
import java.util.List;
import java.util.Set;

@SupportedAnnotationTypes("*")
public class CustomCodeGeneratorProcessor extends AbstractProcessor {
    private Filer filer;
    private Messager messager;
    private Elements elementUtils;
    private Types typeUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnvironment.getFiler();
        messager = processingEnvironment.getMessager();
        elementUtils = processingEnvironment.getElementUtils();
        typeUtils = processingEnvironment.getTypeUtils();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (!roundEnv.processingOver()) {
            try {
                Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(BaseClass.class);
                for (Element element : elementsAnnotatedWith) {
                    TypeElement element1 = (TypeElement) element;
                    List<? extends Element> enclosedElements = element1.getEnclosedElements();

                    MethodSpec main = MethodSpec.constructorBuilder()
                            .addModifiers(Modifier.PUBLIC)
                            .addParameter(Integer.class, "seatCount")
                            .addStatement("this.$N = $N", "seatCount", "seatCount")
                            .build();

                    TypeSpec.Builder builder = TypeSpec.classBuilder("NewCar")
                            .addModifiers(Modifier.PUBLIC)
                            .addAnnotation(AnnotationSpec.builder(ClassName.get("", "ValidPassengerCount")).build())
                            .addMethod(main);
                    outer:
                    for (Element enclosedElement : enclosedElements) {
                        if (enclosedElement.getKind().isField()) {
                            List<? extends AnnotationMirror> annotationMirrors = enclosedElement.getAnnotationMirrors();
                            for (AnnotationMirror declaredAnnotation : annotationMirrors) {
                                if (!typeUtils.isSameType(elementUtils.getTypeElement("A").asType(), declaredAnnotation.getAnnotationType())) {
                                    continue outer;
                                }
                            }
                            builder.addField(TypeName.get(enclosedElement.asType()), enclosedElement.getSimpleName().toString(), Modifier.PUBLIC);

                        }
                    }

                    JavaFile javaFile = JavaFile.builder("", builder.build())
                            .build();

                    javaFile.writeTo(filer);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }


    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

Третий модуль также показан ниже.

Main.class

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;

@CustomCodeGenerator
public class Main {

    public static void main(String[] args) {



        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        NewCar car = new NewCar(-1);

        Set<ConstraintViolation<NewCar>> violationSet = validator.validate(car);
        System.out.println(violationSet.iterator().next().getMessage());

    }
}

ValidPassengerCount.class

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = {ValidPassengerCountValidator.class})
public @interface ValidPassengerCount {

    String message() default "invalid passenger count!";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

ValidPassengerCountValidator.class

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class ValidPassengerCountValidator
        implements ConstraintValidator<ValidPassengerCount, NewCar> {

    public void initialize(ValidPassengerCount constraintAnnotation) {
    }

    public boolean isValid(NewCar car, ConstraintValidatorContext context) {
        if (car == null) {
            return true;
        }

        return 0 <= car.seatCount;
    }
}

Проблема в том, что roundEnv.getElementsAnnotatedWith (BaseClass.class) в CustomCodeGeneratorProcessor.class возвращает пустой список. Если я перенесу автомобиль в 3-й модуль, он заработает. Однако моя цель - создать новый код из базового класса, который поступает из зависимого модуля, который в этом примере является модулем 1. Есть ли способ добраться до аннотированных элементов зависимого модуля?

Методы RoundEnvironment, такие как getElementsAnnotatedWith и getRootElements, не рассматривают уже скомпилированные классы - только те, которые в настоящее время компилируются. Если ваш целевой класс помещен в другой «модуль», он, вероятно, уже будет построен к тому моменту, когда ваш процессор начнет работать, поэтому вы не сможете найти его по аннотации.

user1643723 10.09.2018 15:34
3
1
445
0

Другие вопросы по теме