Working with meta-annotations

Spring framework has the very nice feature of supporting meta-annotations. I wanted to implement the same thing for jTransfo.

The idea is that you can write a custom annotation to replace one or more other annotations. For example in jTransfo, you can define a @ReadOnly annotation which replaces @MappedBy(readOnly = true).

You can define the custom annotation like this:

@MappedBy(readOnly = true)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Documented
public @interface ReadOnly {
 
}

Note that this annotation can itself also be used as meta-annotation thanks to the ANNOTATION_TYPE target.

To check whether an annotation exists on a field or method, you need to read through the chain. This can be done using this code:

    /**
     * Get the annotations of given type which are available on the annotated element. Considers both the annotations
     * on the element and the meta-annotations (annotations on the annotations).
     * The result is given in no specific order
     *
     * @param element annotated element
     * @param annotation annotation to find
     * @param <T> annotation type
     * @return
     */
    public <T extends Annotation> List<T> getAnnotationWithMeta(AnnotatedElement element, Class<T> annotation) {
        return (List) Stream.of(element.getDeclaredAnnotations())
                .flatMap(this::addMetaAnnotations)
                .filter(a -> annotation.isAssignableFrom(a.annotationType()))
                .collect(Collectors.toList());
    }
 
    private Stream<Annotation> addMetaAnnotations(Annotation a) {
        Set<Annotation> res = new HashSet<>();
        addMetaAnnotations(res, a);
        return res.stream();
    }
 
    private void addMetaAnnotations(Set<Annotation> set, Annotation annotation) {
        if (set.add(annotation)) { // set is needed or continues infinitely
            for (Annotation meta : annotation.annotationType().getDeclaredAnnotations()) {
                addMetaAnnotations(set, meta);
            }
        }
    }

Leave a Reply

Your email address will not be published. Required fields are marked *

question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen

*