简体   繁体   中英

How to make a custom annotation inherit other annotations

I created a custom annotation, for a custom data type. Currently my entity looks like this:

@Entity
public class contact {

    @Valid
    @Randomizer(EmailAddressValidator.class)
    @EmailAddressField
    @Convert(converter = EmailAddressConverter.class)
    @JsonSerialize(using = EmailAddressSerializer.class)
    @Column(name = "email")
    private EmailAddress email;
}

But I would like to have the following

@Entity
public class contact {

    @EmailAddressField
    @Column(name = "email")
    private EmailAddress email;
}

What do I have to do in my own annotation, so that I don't have to write the other annotations for each property?

I would like to have everything together and only have to write one annotation to the property, for clarity.

My annotation currently looks like this:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE_USE})
@Constraint(
    validatedBy = {EmailAddressValidator.class}
)
@Documented
public @interface EmailAddressField {
    Class<?>[] groups() default {};

    String message() default "No Email Address";

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

But if I change that to this it doesn't work:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE_USE})
@Constraint(
    validatedBy = {EmailAddressValidator.class}
)
@Documented
// -- Annotations from property
@Valid
@Randomizer(EmailAddressValidator.class)
@Convert(converter = EmailAddressConverter.class)
@JsonSerialize(using = EmailAddressSerializer.class)
@Inherited
// --
public @interface EmailAddressField {
    Class<?>[] groups() default {};

    String message() default "No Email Address";

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

Java annotations are interfaces that can be applied to methods, classes, and fields and they are not capable of having other annotations as values because they are not objects, they are a form of metadata that don't have any methods or states and their main purpose is to provide metadata that can be read and processed by other tools such as the Java compiler or JVM.

A possible solution to avoid writing the following boilerplate codes would be creating a custom annotation processor that uses the AbstractProcessor class from the javax.annotation.processing package . This would allow you to define custom annotations and specify the actions that should be taken when they are encountered in your code during the compile time.

Here is the documentation; https://docs.oracle.com/en/java/javase/11/docs/api/java.compiler/javax/annotation/processing/Processor.html https://docs.oracle.com/en/java/javase/11/docs/api/java.compiler/javax/annotation/processing/AbstractProcessor.html

Add following dependencies in the gradle, for configuruing @AutoService

dependencies {
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc5'
    compileOnly 'com.google.auto.service:auto-service:1.0-rc5'
}

And here is the sample code;

@AutoService(Processor.class)
@SupportedAnnotationTypes("com.example.EmailAddressField")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EmailAddressFieldProcessor extends AbstractProcessor {

    private Elements elementUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.elementUtils = processingEnv.getElementUtils();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement annotation : annotations) {
            for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
                if (element.getKind() == ElementKind.FIELD) {
                    VariableElement field = (VariableElement) element;
                    AnnotationMirror validAnnotation = elementUtils.getAnnotationMirror(Valid.class);
                    field.getAnnotationMirrors().add(validAnnotation);
                    AnnotationMirror convertAnnotation = elementUtils.getAnnotationMirror(Convert.class);
                    field.getAnnotationMirrors().add(convertAnnotation);
                    // BlahBlah.class annotation..... etc...
                }
            }
        }
        return true;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM