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