Gregor Riegler

About 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.

An Annotation Nightmare

 
 
 
 
 
 
 
 
 
 
 

@XmlElementWrapper(name="orders")
@XmlJavaTypeAdapter(OrderJaxbAdapter.class)
@XmlElements({
   @XmlElement(name="order_2",type=Order2.class),
   @XmlElement(name="old_order",type=OldOrder.class)
})
@JsonIgnore
@JsonProperty
@NotNull
@ManyToMany
@Fetch(FetchMode.SUBSELECT)
@JoinTable(
    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

@Inject
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());
this.testContextManager.prepareTestInstance(this);

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.

@Override

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

@SuppressWarnings

… Don’t even get me started

tl;dr

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.


@DevNull({

 @SuppressWarnings

 @Autowired, 
 @Inject, 

 @Override,  

 @XmlElementWrapper,
 @XmlJavaTypeAdapter,
 @XmlElement,
 @JsonIgnore,
 @JsonProperty,
 @ManyToMany,
 @Fetch,
 @JoinTable
})

 

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

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

9 Responses to "An Annotation Nightmare"

  1. Valeriy says:

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

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

      ?

      • Valeriy says:

        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 ?(http://en.wikipedia.org/wiki/Single_responsibility_principle) 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 https://github.com/spring-projects

        • Gregor says:

          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 misunderstanding here what the responsibility is?

          the entity is our business object. the responsibilities are:
          – mapping it to the database
          – (de)serializing it to/from json
          – (de)serializing it to/from xml
          these are all just strategies, possibly reflecting a strategy pattern.

          if we want to make this clean, we keep a single entity, and implement the responsibilities in mappers / serializers.

          • Valeriy says:

            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 ever counted how much garbage were created by a third party library you used, or how much data stayed in cache of you ORM framework ?

            All I mentioned is just different vision of things by another developer, I do not insist that I am the right one.

            Thanks for interesting article, there is what to think about.

  2. Greg says:

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

  3. Sid says:

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

  4. Bill says:

    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 or duplicate the field definition itself. Purists complained about polluting the domain model with framework configuration, but who cares enough to stick with .hbm.xml files?

    The only way I could think of improving this in pure Java is for frameworks to let you put the annotations in a static inner “meta” class similar to Python/Django – so you have a way to separate configuration for each framework to its own section of the file syntactically. The field definition in the main part of a Django model class contains persistence, but customization of the fields for the admin UI happens separately.

Leave a Reply


4 − = zero



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close