News: @Composite - Macro Annotations for Java

  1. @Composite - Macro Annotations for Java (2 messages)

    Some months ago I attended a presentation at which Wilfred Springer demonstrated his very cool Preon binary codec library. Defining binary file formats in Preon requires quite a lot of fairly repetitive sets of annotations, and during a chat after the talk Wilfred mentioned how much more convenient it would be if one could just define "shortcuts": @RequiredEnumProperty(column = "AGENT") for @NotNull @Column(name = "AGENT") @Enumerated(EnumType.STRING) for instance - and use those instead. Sort-of "macro annotatations" for Java, if you like. A thought that has presumably also occurred to many frequent users of Hibernate, JAXB or other annotation-heavy frameworks. Hence @Composite. Just to dispel any misconceptions up front: here be no bytecode weaving or other runtime magic, so @Composite does not affect the semantics of the "regular" AnnotatedElement methods. Composite annotations are instead supported via an AnnotatedElements interface, which provides all the familiar annotation-related methods, and "unpacks" registered composite annotations to their "leaf" types. So @Composite is not (yet) drop-in magic - you will need to explicitly call the AnnotatedElements interface from your code. The AtCompositeDemo class included in the project basically looks like this: public class AtCompositeDemo { ... // define a composite annotation @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) @CompositeAnnotation public @interface TargetRetentionLeafCompositeAnnotation { boolean runtimeRetention() default false; @LeafAnnotation Target targetLeafAnnotation() default @Target({ ElementType.METHOD }); @LeafAnnotation(factoryClass = RetentionLeafAnnotationFactory.class) Retention retentionLeafAnnotation() default @Retention(RetentionPolicy.RUNTIME); } // apply the composite annotation... @Resource @TargetRetentionLeafCompositeAnnotation(runtimeRetention = true) private static @interface AnnotatedAnnotation {} // ...to two targets @Resource @TargetRetentionLeafCompositeAnnotation(runtimeRetention = false) private static @interface OtherAnnotatedAnnotation {} public static void main(String[] args) { // get a configured instance of the AnnotatedElements interface AnnotatedElements annotatedElements = ... log.info("Retrieving annotations from AnnotatedAnnotation.class"); log.info(Arrays.toString(annotatedElements.getAnnotations(AnnotatedAnnotation.class))); log.info("Retrieving annotations from OtherAnnotatedAnnotation.class"); log.info(Arrays.toString(annotatedElements.getAnnotations(OtherAnnotatedAnnotation.class))); } } When run, it should produce output similar to the following Retrieving annotations from AnnotatedAnnotation.class [@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER), @java.lang.annotation.Retention( value=RUNTIME), @java.lang.annotation.Target(value=[METHOD])] Retrieving annotations from OtherAnnotatedAnnotation.class [@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER), @java.lang.annotation.Retention( value=CLASS), @java.lang.annotation.Target(value=[METHOD])] which demonstrates the key features of @Composite: namely, that the composite annotation is correctly "expanded" into a @Target and a @Retention annotation, and the "regular" @Resource annotation is still picked up. More details can be found in the following blog post. The code itself is available at Google Code.
  2. Annotations are currently overdone in Java, just like XML a few years ago.
  3. It is really overdone and will significantly increase the complex of Java in the future. Several years ago, I ever said the annotation is not a good idea. Somebody ever thought I was stupid. Also, the Java maybe get out of control. Now the application code has been bound to the vendor and difficult to migrant it from one to another.