I’ve discovered this recently while looking into some issues caused by the Jackson libraries in one of my Java applications. If you use Jackson I’m sure you are by now familiar with some of the annotation they supply — such as
@JsonCreator — and it was dealing with these that got me to make this small (yet important I think) discovery in the JDK.
The scenario is this: you have your bean class and you have your setters and getters set up and everything looks good. You add Jackson to your app so you can offload the JSON serialization and deserialization to this library and all works well. And then you realize that really you want to implement immutable beans — and as such you would like to get rid of the setters in your bean code. You change your code (and your bean!) so you supply arguments in your bean constructor which sets the bean inner (final!) fields and then never to be changed again such that you can have a truly immutable bean class. You have however one problem left: your JSON deserialization through Jackson now fails!
The reason for it is that by default Jackson will employ a Java bean pattern for deserialization: first create an instance of the bean class by using the default (or zero args) constructor and then employ a series of callers to the setters to set each property value. Except that now you don’t have any setters anymore! (And quite likely you have removed the zero args constructor too.)
So typically what you have to do now is rely on the Jackson annotations:
@JsonProperty — something like this:
The problem is as much as I use these 2 annotations in conjunction a lot, I don’t like the result code! I don’t like it because it’s very Jackson specific and it also has references (in the names of the annotations) to JSON (specifically!) serialization. I am not coming at this issue from the angle of “if I ever need to change the JSON serialization framework” because it would be silly: once you choose your framework, especially if it’s a mature framework, there is no reason to change that, so no, that’s not what worries me about these annotations being Jackson specific. Let’s say that I use this bean in more than one part of my app: in one part of the app I am serializing it to JSON whereas in another part I might choose a different serialization mechanism (say YAML?). As such, since Jackson doesn’t support YAML I will have to use a different framework for serializing these beans — and those libraries will quite likely require their own (similar) set of annotations. So now my (very simple!) Java bean gets decorated with a ton more annotations just to support another serialization framework.
And also, as I said, this suggests that these annotations only work when dealing with JSON formats — though as it turns out in the case of Jackson the same annotations work for when dealing with XML (which Jackson supports). If I give this code to a colleague who doesn’t have knowledge about Jackson and I ask them to add support for XML for instance, their initial thinking upon encountering these annotations is that we need more code / frameworks / etc to support XML as the current code (misleadingly) states it only supports JSON.
So, as I said before, I used these annotations together a lot as it allows me to implement my beans as immutable — even though technically by doing this they break the Java bean contract and are no longer proper Java beans — but I don’t like them. And in search for a better alternative I came across an awesome annotation in the JDK:
@ConstructorProperties ! Yes, you read this correctly: in the JDK! This means that it’s independent of the libraries I use — so (nice) frameworks dealing with these cases can (should!) make use of this annotation where present. And in fact Jackson from version
2.7 onwards supports this (see their release notes here: https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.7)
The way this works is very simple: rather than annotating each parameter in the constructor, you provide an array with the properties names for each of the constructor parameters. So parameter in position 0 will be matched to name of the property in position 0 in the given array, parameter 1 with property in position 1 in array and so on. Something like this:
First of all this is less code to write 🙂 Secondly, as long as all the serialization frameworks are aware of this annotation and using it properly (quick search seems to indicate that is the case, as I said, Jackson libs already support this) then I shouldn’t have to apply any other annotations to my beans. Ever! 🙂