3

我的目标是通过注释处理器生成代码。我想通过根据注释排除一些字段并添加一些约束验证器等,在现有基类的顶部生成新类。我有 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();
    }
}

第三个模块也如下所示。

主类

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;
    }
}

问题是 CustomCodeGeneratorProcessor.class 中的 roundEnv.getElementsAnnotatedWith(BaseClass.class) 返回空列表。如果我将 Car 移到第三个模块中,它就可以工作。然而,我的目标是从来自依赖模块的基类生成新代码,对于这个例子来说,它是模块 1。有没有办法到达依赖模块的注释元素?

4

0 回答 0