Core Java

An Annotation Nightmare


    name = "customer_order",
    joinColumns = {
        @JoinColumn(name = "customer_id", referencedColumnName = "id")
    inverseJoinColumns = {
        @JoinColumn(name = "order_id", referencedColumnName = "id")
private List orders;

Wait. What? Is this really what we have come to? I can’t even see the damn property under this bloat. How did this happen? Yeah ok – we had to get rid of the old xml configuration horror somehow. But this? This is even WORSE. This class is supposed to be a goddamn pojo with a bunch of properties. Short and concise, easy to read. I, as a reader of this cass, am not interested at all how the database table is joining customers to orders. I’m neither interested how its being serialized. This is just implementation details. Reading this class, i am living in an object world and i want to know what data and behaviour the object has. Not more, not less. I don’t care about column names, fetchtypes or json serialization for the moment. And i don’t want to read, change or recompile this class for the sake of a tablename change. I don’t want to add another annotation for storing this entity in a mongoDB neither. The entity should not have responsibility for these details. We are not only violating the Single Responsibility Principle here, we are doing a f****** responsibility party.

Ok ok, enough of the rage. How do we deal with this issue? Some duplicate the entity for various layers with different annotation purposes. They map the entity onto the next layers related entity using an automated mapper like Dozer. Some even write that mapping themselves. But this is by no means a solution. It is just replacing one code smell with another one: Duplication.

So please, focus on frameworks that don’t force you to clutter your code. jOOQ is a nice solution to map database records to entities without annotations. Also, hibernate allows you to define your mappings in XML.

Private Field Injection

private MyService myService

This is used quite often, while it shouldn’t even be possible. The myService field is private, thus it’s inaccessible from outside the class. Nevertheless it’s possible and people do it. In reality it is a hack. The DI-framework sets the field using reflections doing setAccessible(true). You don’t want hacks in your code, do you? Lets have a look at the alternatives:

Setter Injection

Well, at least its better than the private field injection, since its using a public method instead of hacking a private field. But still, ask yourself this: ‘Is this class even supposed to live without the injected value?’ Because if it’s not, there is no reason what so ever for the class to get constructed without an instance of MyService. You want to implement this constraint on the class level and inside the constructor, not on the framework level.

Constructor Injection

This is usually the way to go. It allows you to

  • make the field immutable (there is usually no need to change it).
  • implement the constraint, that the class is not instantiatable without a given MyService in the right place.

Of course it means that you cannot inject by annotation. But why would you want to? The class doesn’t need to know, if it gets injections by a DI-Container or a Factory Class. It should not know anything of this. No @Autowired, no @Qualifier. All it needs to know is its own behaviour. Everything else should be handled outside of the class.

One could use a configuration class or file for the actual injection.

A DI-Container is a usefull tool that helps you wire your classes together. Use it for this purpose, but don’t let it dictate your code. Uncle Bob wrote a great post where he explained how to use DI-Frameworks without having them dictate your code.

@RunWith(SpringJUnit4ClassRunner.class) in UnitTests

Why would you need this in unittests? Because it is automatically generated by your IDE/app template? No! You want to test the behaviour of a class, living in isolation in unittests. Not if the DI-Conainer is injecting a fields accordingly. Just inject yourself in a setup method. No DI-Container needed. By the way, all this testrunner does is these 3 lines of code.

private TestContextManager testContextManager;
this.testContextManager = new TestContextManager(getClass());

They are not worth blocking your only TestRunner slot. You want to keep it free for something like parameterized @RunWith(JUnitParamsRunner.class) or concurrency @RunWith(ConcurrentJunitRunner.class) tests.


Really, my IDE already knows if i am correctly overriding a method. To me, its just clutter.


… Don’t even get me started


Annotations have become more harmful than helpful these days. We should get back to pojos and focus on keeping our code as clutterless and framework-agnostic as possible to make it more readable and reuseable. Don’t let frameworks dictate your codebases, since they should be exchangable tools. Beware of what a class should know, and what not. Some annotations are useful, most aren’t.







Reference: An Annotation Nightmare from our JCG partner Gregor Riegler at the Be a better Developer blog.

Gregor Riegler

Gregor is a passionate software engineer and RESTafarian who loves to continuously improve. He is interested in modern web development, oo-design and extreme programming. He is also serious about clean code and TDD.
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Newest Most Voted
Inline Feedbacks
View all comments
10 years ago

Actually all issues that you mentioned are results of bad design or annotation misusing. There are a lot of good examples where annotations lead to simple and clean code.

Valery Silaev
Valery Silaev
10 years ago
Reply to  Valeriy


I’m intrigued. Could you provide a concrete example when “annotations lead to simple and clean code” given the same requirements as in article:
1. The demo class must be a JPA entity.
2. It should be serializable to several formats (XML, JSON, CSV…)


10 years ago
Reply to  Valery Silaev

You want to have one entity that will end up responsible for everything, save data to DB, convert to XML, convert to JSON, convert to CSV, or PDF etc. This looks like complete violation of single responsibility principle is not it ?( It is better to have a number of converters which will do their single responsibility of conversion and will be easy to test and customize for future use. Also you will separate all conversion details in converter so code will look cleaner in general. For good examples of coding you can look here

10 years ago
Reply to  Valeriy

so you are saying, one should have 1 entity for the db 1 entity for xml serialization 1 entity for json serialization 1 entity for …. and you convert between all of them, yet you have only one responsibility per entity. but now tell me. arent all these entities just duplicates of each other? is the vast amount of boilerplate code to convert and transport the entities then clean? is it reasonable, to have the same object 3 times in memory all with the same values, just to separate the entities – isnt that a waste of memory? aren’t we… Read more »

10 years ago
Reply to  Gregor

In practice, entity for DB interaction is different from that used for JSON serialization, different needs has different requirements. Much clearer to see them separate. As for me it will not be easy to see why so many mapping was applied to one field, and what to do if I need to rename that field. With that strategy you mentioned it i easy to end up with one monster entity more that 1k lines size. About boilerplate code, do you prefer to have one god converter for everything ? It sounds like one Class application. About memory wasting, have you… Read more »

10 years ago

I like @Override. I’m curious now. How does your IDE detect that you misspelled a method that you wanted to override?

10 years ago
Reply to  Greg

it was clarified in the original posts commentaries, that @Override can indeed be very helpful in large projects for example.

10 years ago

Somehow I like @Override. Tells which methods are overridden immediately, although IDE displays a small up arrow on the left.

10 years ago

I feel like the annotation bloat may be the least-bad option in pure Java – dynamic JVM languages like Groovy give you so many more options. And I’m glad you point out duplication is even worse. The problem with annotations is like a tragedy of the commons: it’s a great idea until everyone else does it too. Then you get this clutter of all these unrelated things (JPA, JSON, XML) in one place. When JPA/Hibernate was the main (or only) reason you had field-level annotations, it was a win: you don’t have to jump back and forth between two files… Read more »

Back to top button