Annotations, Annotations Everywhere
Annotations became available with Java 1.5 in 2004, ten years ago. It’s hard to imagine our code without this feature. In fact, annotations were first introduced to relieve developers from the pain of writing tedious boilerplate code and make the code more readable. Think about J2EE 1.4 (no annotations available) and Java EE 5. Annotation adoption considerably simplified the development of a Java EE application by getting rid of all the configuration XML. Even today, more annotations are being added to the newest version of Java EE. The idea is to unburden the developer and increase productivity. Other technologies and frameworks use them extensively as well.
Annotations Everywhere
Let’s see an example on how annotations have simplified our code (from my post about JPA Entity Graphs):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | @Entity @Table(name = "MOVIE_ENTITY_GRAPH") @NamedQueries({ @NamedQuery(name = "Movie.findAll", query = "SELECT m FROM Movie m") }) @NamedEntityGraphs({ @NamedEntityGraph( name = "movieWithActors", attributeNodes = { @NamedAttributeNode("movieActors") } ), @NamedEntityGraph( name = "movieWithActorsAndAwards", attributeNodes = { @NamedAttributeNode(value = "movieActors", subgraph = "movieActorsGraph") }, subgraphs = { @NamedSubgraph( name = "movieActorsGraph", attributeNodes = { @NamedAttributeNode("movieActorAwards") } ) } ) }) public class Movie implements Serializable { @Id private Integer id; @NotNull @Size(max = 50) private String name; @OneToMany @JoinColumn(name = "ID") private Set<MovieActor> movieActors; @OneToMany(fetch = FetchType.EAGER) @JoinColumn(name = "ID") private Set<MovieDirector> movieDirectors; @OneToMany @JoinColumn(name = "ID") private Set<MovieAward> movieAwards; } |
Wait a minute! Simplified? Really? Aren’t annotations supposed to make my code more readable? This example has more annotations than actual code. To be fair, I’m not including getters and setters. Also, some of the annotated code could be better condensed, but it would make the code harder to read. Of course, this is an extreme case. Anyway, I’m happy since I won the title Annotatiomaniac of the Year. Thanks Lukas!
We rely in annotations so much that we end up abusing them. It’s funny that annotations in some cases are causing the same problems that they intended to solve.
What if?
Let’s rewrite the previous sample like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @MovieEntity @FindAll @LoadWithActors @LoadWithActorsAndAwards public class Movie implements Serializable { @Id private Integer id; @Name private String name; @MovieActors private Set<MovieActor> movieActors; @MovieDirectors private Set<MovieDirector> movieDirectors; @MovieAwards private Set<MovieAward> movieAwards; } |
It sure looks more readable. But these annotations do not exist. Where do they come from?
@LoadWithActors
1 2 3 4 5 6 7 | @NamedEntityGraph( name = "movieWithActors", attributeNodes = { @NamedAttributeNode("movieActors") } ) public @interface LoadWithActors {} |
@LoadWithActorsAndAwards
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @NamedEntityGraph( name = "movieWithActorsAndAwards", attributeNodes = { @NamedAttributeNode(value = "movieActors", subgraph = "movieActorsGraph") }, subgraphs = { @NamedSubgraph( name = "movieActorsGraph", attributeNodes = { @NamedAttributeNode("movieActorAwards") } ) } ) public @interface LoadWithActorsAndAwards {} |
And so on for the rest. You get the feeling. The idea would be to extract and group annotation metadata into your own custom annotations. Your annotation could then be used to represent all the annotated data in your code, making it easier to understand. It’s like Java 8 Lambdas, read like the problem statement.
Just another example:
1 2 3 4 5 6 7 8 | @Named @Stateless @TransactionAttribute(TransactionAttributeType.SUPPORTS) @ApplicationPath("/resources") @Path("wowauctions") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class WoWBusinessBean extends Application implements WoWBusiness {} |
Rewritten:
1 2 | @RestStatelessBean("wowauctions") public class WoWBusinessBean extends Application implements WoWBusiness {} |
@RestStatelessBean
1 2 3 4 5 6 7 8 9 10 | @Named @Stateless @TransactionAttribute(TransactionAttributeType.SUPPORTS) @ApplicationPath("/resources") @Path("#{path}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public @interface RestStatelessBean { String value() default "#{path}"; } |
Usually, I write these annotations once to define the behaviour of my POJO and never look into them again. How cool would be if I could just reuse one annotation for all my Stateless Rest Services?
Another nice effect, is that annotation configuration metadata is not directly tied in the code. Instead it’s abstracted away into a different annotation. In this case, it would be possible to override or replace the values in compile / runtime.
Meta Annotations
I first heard about this concept by David Blevins. He wrote a very good post about these ideas in his Meta-Annotations post and even wrote a possible implementation.
It would be convenient to have plain Java SE support to annotation inheritance, abstraction and encapsulation. It’s a major shift in the way annotations are handled by all the technologies out there. This only makes sense if everyone starts supporting this kind of behaviour.
One might ask, do we really need this feature? Let’s try to weigh in some pros and cons:
Pros
- Simplified Code.
- Annotation Reuse.
- Annotation configuration not directly tied to the code. Values could be overridden.
Cons
- Another layer of abstraction.
- Freedom to create custom annotations could obfuscate the real behaviour.
- Possible to run into some kind of multiple inheritance pitfall.
Conclusion
It’s unlikely that this Meta-Annotations are going to be available in Java SE for the foreseeable future. In Java 9, most of the focus is in Jigsaw. We don’t have much information yet on Java 10, other than Value Types and Generic Specialization. In fact, all these annotation concerns are not really a problem for plain Java SE.
The amount of annotations present in our source files is becoming a problem regarding readability and maintainability. This is especially true for Java EE and other similar technologies. Think about HTML and CSS. If you’re developing an HTML page and you only need a couple of CSS styles, you usually inline them in the elements or include them directly in the page. If you start to have too many styles, then you proceed to extract them into an external CSS file and just apply the style. I do believe that something must be done either by adopting Meta-Annotations or something else. Do you have any other ideas? Please share them!
Resources
Don’t forget to check David Blevins post about Meta-Annotations. He explains this much better than me, including the technical details.
Also a presentation JavaOne EJB with Meta Annotations discussing these ideas by David Blevins.
And what better than to listen David Blevins himself? Java EE 7, Infinite Extensibility meets Infinite Reuse.