Bug in Jackson JSON serialization of Immutable objects


The bug

I have been using Jackson for JSON processing for many years now. It is a great framework and mostly just works. It is the default framework in Spring Boot and mostly it just sits behind the scenes and drives most micro services in Java these days. That is why I was surprised when we hit a bug in the framework as I hadn’t really had any issues in the past.

The backstory

Anyone who has coded with me knows that I tend to favor immutability for most java objects. By default I make everything final and then only has non final things when they are necessary. This principle is documented in Effective Java Second Edition Item #15. As a side note everyone should read that book. Even senior developers benefit greatly flipping through the book once a year and reviewing the items. It may be the best Java book I have ever read for writing very good code. My hope is that Josh Bloch does a 3rd edition to cover all the new functional operations in the language.

The best way that I have found to create Immutable Data Transfer Objects in Java with Jackson is to have all the fields be final values, and to annotate the constructor with @JsonCreator and each property in the constructor with @JsonProperty("propertyName"). Just like that you have an object that won’t change state and works seamlessly between your Java Service and your JavaScript front end or between 2 Java back end services.

The problem

The problem we found with this approach occurred in an integration with another partner. Our developer was trying to use Java best practices so the variables are camel case and he is using @JsonCreator in the constructor and naming the properties there. While that works great for an inbound object when trying to serialize that object out to JSON Jackson is throwing away those property names and serializing off of the field name. Normally our field name matches our property name so this is no issue. But in this case the property on the other side was something like first_name, but we record the variable as firstName. Jackson is serializing that as firstName if you only use the Constructor approach. If you add @JsonProperty("first_name") to the field it will work. So you are basically left either double annotating the field or going with a mutable POJO object to get the correct output. I have created a project on github demonstrating the problem:

https://github.com/haskovec/jackson-serialization-bug

Additionally I have opened an issue on the Jackson project for anyone who is interested in following this issue. So far I haven’t heard anything back on it.

Closing thoughts

So the real question is how did this thing go through without getting caught. My suspicion is that most developers don’t actually create Immutable objects in general. The other possibility is that people don’t often have an output that doesn’t match the variable names. We could take the ugly approach and declare final String first_name; to fix it but that doesn’t make me happy either.

I will be interested in seeing if anyone responds to the issue and what they say. I think it is always a good test of a project to see how active it is by seeing how long it takes for the developers of the project to at least comment on a given issue found in their code. I did a little bit of debugging into the Jackson code and I can see where it is throwing away the correct property values, but I am not sure what the correct fix is. It feels like a method that if I tried to fix I could easily break some other use case.

Update

Turns out it wasn’t a bug and I got great help on the team to fix the issue.


One response to “Bug in Jackson JSON serialization of Immutable objects”