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):

Movie.java

Java

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")

}

)

}

)

})

publicclassMovieimplementsSerializable{

@Id

privateIntegerid;

@NotNull

@Size(max=50)

privateStringname;

@OneToMany

@JoinColumn(name="ID")

privateSet<MovieActor>movieActors;

@OneToMany(fetch=FetchType.EAGER)

@JoinColumn(name="ID")

privateSet<MovieDirector>movieDirectors;

@OneToMany

@JoinColumn(name="ID")

privateSet<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:

Movie.java

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

@MovieEntity

@FindAll

@LoadWithActors

@LoadWithActorsAndAwards

publicclassMovieimplementsSerializable{

@Id

privateIntegerid;

@Name

privateStringname;

@MovieActors

privateSet<MovieActor>movieActors;

@MovieDirectors

privateSet<MovieDirector>movieDirectors;

@MovieAwards

privateSet<MovieAward>movieAwards;

}

It sure looks more readable. But these annotations do not exist. Where do they come from?

@LoadWithActors

LoadWithActors.java

Java

1

2

3

4

5

6

7

@NamedEntityGraph(

name="movieWithActors",

attributeNodes={

@NamedAttributeNode("movieActors")

}

)

public@interfaceLoadWithActors{}

@LoadWithActorsAndAwards

LoadWithActorsAndAwards.java

Java

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@interfaceLoadWithActorsAndAwards{}

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:

WoWBusinessBean.java

Java

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)

publicclassWoWBusinessBeanextendsApplicationimplementsWoWBusiness{}

Rewritten:

WoWBusinessBean.java

Java

1

2

@RestStatelessBean("wowauctions")

publicclassWoWBusinessBeanextendsApplicationimplementsWoWBusiness{}

@RestStatelessBean

RestStatelessBean

Java

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@interfaceRestStatelessBean{

Stringvalue()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

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!

Comments ( 17 )

Roberto, I cannot agree that all the focus of Java SE 9 is on Jigsaw. Yes, this is the biggest topics, but JEP-wise, it’s just 4 JEPs, out of ~20 that are approved to enter Java 9 (for now). And the game is not over yet.

But you are right, this topic is not in Java SE yet and I don’t see it discussed to go there. 🙂

Some annotations like @override or the one of lombok project seems good to me since you can not achieve the same in pure java. Even JPA seems ok since it would be tedious to do that separately from the fields.

For the rest I far too often feel like I’m writing annotations and not code.

The worst (to me) is DI annotation like @Inject or @Autowire that leads to object with tens of collaborators (who would write a constructor with 10 args ?)

Fun aside, annotations can (and will) be overused. I even think that the validation JSR is more dangerous in a way that people think they should rely on annotations to assure consistency in their domain model instead of value objects. See this one for a frightening example. All of these annotations should be value objects instead. An IBAN is an IBAN is an IBAN, not a String with an annotation. Anyway, I digress…

The concept of meta-annotation has been a first class citizen in Springs since the early days it leveraged annotations in general (2.5.6, read: 2008). So pretty much all Spring annotations can be used that way. The standards have been pretty hesitant in that regard, although they actually leveraged annotations even earlier than Spring did. Only a very few of them (I only know about some in the @Inject but would be happy to find out about other ones as well) support that kind of style.

For JPA named entity graphs it’s a particular pity as I pointed out that the declarations might quickly get out of hand in the early design phase within the expert group. Especially as the specification (and also your example) usually only deal with very simplistic examples. Now imagine what this looks like if you use that in a real-world application where you list 10 out of 15 properties.

The feedback I got was that a simplification step (I suggested just alternatively taking a String-array to be able to easily whitelist the properties to be included but still provide the more verbose way for more complex scenarios) could be added if people would really complain. So I suggest to create a ticket in the spec’s bugtracker if you think it’s worth simplifying. I already raised one to add the ability to use the annotations as meta-annotations a while ago.

@cblin – It’s not really an issue with DI, but field injection. But agreed, if the annotations would not have been allowed to be used on fields in the first place, the world would be a better place today. See my rant on this one here :).

Meta annotations are not fixing the problem, just treating the symptoms.

There are many things we annotate that could just as easily be defined in a .java file using some library api, for instance Spring bindings vs Guice bindings. Guice has significantly less annotations than Spring.

The problem is annotations have become our crutch for everything config. We forget that plain jane java code is the best config of all, it can loop, it can connect to external sources and anything else we can dream of. Give people a proper api to configure your library and they can accomplish all sorts of problems they can’t with just some annotations.

Thank you for your comment. Maybe meta annotations are not the perfect solution, but something must be done. At least they could shield the average developer with the ridiculous amount of annotation that you have to know and type each day. Even today I was looking into a Spring file which had @Configuration and @EnableAutoConfiguration. I know they are different, but also confusing.

Plain java configuration also haves the advantage of being more readable, since you can just follow a stack of execution. Annotations are a pain in that department.

Hi Roberto, thanks for the tutorial. However could you provide an example of how you created any of the @MovieDirectors, @MovieAwards or @MovieActors custom annotations? I’ve been trying something similar where I want to group a number of JPA annotations into my own custom annotation i.e.

Unfortunately the standard JPA annotations cannot be used into other annotations because they don’t have the @Target(ElementType.ANNOTATION_TYPE). This post was just an idea on how to improve these annotations and remove annotations from the code.