Search code examples
javaspringannotationsaoplombok

Is it possible to create an annotation bundle in java (i.e. an annotation that applies other annotations)?


Assume the following code is seen frequently in a codebase:

// old wet code
@AnnotationA
@AnnotationB
@AnnotationC
class SomeClass {
   // ...
}

Is it possible to create an annotation AnnotationBundle that applies the other annotations (A, B, C) and generates the same functionality? This would only be used to DRY the codebase and not accidentally forget a single annotation on a class.

// new DRY code
@AnnotationBundle
class SomeClass {
   // ...
}

Solution

  • Short answer

    No, you cannot. There is no concept of meta annotations in Java as such.

    Alternative 1: Spring annotations

    Someone mentioned Spring meta annotations. Yes, in Spring you can do this, but only because Spring implements some quite impressive internal machinery involving reflection and other mechanisms in order to implement the concept. So

    • either you use Spring and rely on its capabilities,
    • or you rebuild something similar and make sure that your own applications use the framework you are building
    • or you extract the Spring annotation stuff and use it outside of Spring.

    I did the latter a while ago as a finger exercise because I wanted to see if it is even possible to extract it. It was quite difficult because it is entangled quite deeply with other Spring stuff, but in the end I managed to do it.

    The result is here, a stand-alone version of Spring annotation utilities usable outside of Spring. If you read the readme, you can learn how I did it because I documented it as a template for similar extractions in the future. I actually never used my own stand-alone Spring annotation utilities, but I am inviting you to do so. There are many more things Spring can do with annotations, e.g. check if there are annotations on interfaces implemented by a class, annotations on super class methods etc. This is quite powerful and explains why Spring can implement some annotation-based stuff which are impossible with the JRE out of the box. E.g. the JDK has no concept of inheriting annotations except (optionally) from superclass to subclass, but not from interface to class and not from method to overriding method.

    You can just clone and build my GitHub repository and see if it helps you do the things you want to do. But it won't magically happen by itself, you have to call the corresponding methods in order to gather information like that.

    Alternative 2: AspectJ

    As an alternative, you can use AspectJ (I am talking about real AspectJ, not Spring AOP) and use ITD (inter-type definitions) in order to e.g. make a class implement an interface or declare annotations on a type. This way you could implement an aspect emulating meta annotations. The aspect would take care of everything, the application would not need to know about it. I am not sure if you want to learn AOP in order to do this, though.