我的目标是通过注释处理器生成代码。我想通过根据注释排除一些字段并添加一些约束验证器等,在现有基类的顶部生成新类。我有 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。有没有办法到达依赖模块的注释元素?