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.

TIL: default hashCode() in Java

I came across this blog post today which I thought was really good. It is a deep dive into the default hashCode() implementation in java. To me the most amazing outcome of the piece is that if a given class is going to be accessed by multiple threads you really need to override hashCode otherwise biased locking is disabled. All in all it is an interesting look in the guts of the JVM and worth a read: default hashCode

AWS Lambda or should I call them nano services?

Recently at work I worked on a project using Amazon AWS Lambda. This is a cool concept. Amazon calls it serverless computing, but really what it is, is abstracting the server so that you can just focus on a small task that needs to run.

In this case we had a rest endpoint that just stores some data in a database.  If we think about a traditional Spring Boot Microservice we would probably do Spring Data JPA, point it at a mysql DB, and then have some rest controllers that talk to a service tier which persists the data. With Spring Boot this isn’t much code, but you still have some embedded Tomcat Server and a fair amount of ceremony for doing something very simple. After building the app you will need to deploy it to Elastic Beanstalk instance or else an EC2 Nano Instance or something similar. That is a lot of DevOps overhead to do something very simple. With Lamdba we can create a simple class that takes a pojo java object (Jackson style). With Lambda you don’t have Hibernate, you are just dealing with raw JDBC but when you are just inserting 1 Row into a Database you don’t really need am object relational mapping. You then use Amazon’s API gateway to send any requests to an endpoint to the lambda function and you are all good to go.

That got me thinking S3 now has the ability to serve an S3 bucket as a website, so you could drop an angular app into an S3 bucket and serve that up and then point it at API Gateway which then hits a Lambda and talks to an RDS instance. If your site didn’t have much traffic it would be a super cheap way to host it as Lamdba is billed based on how much compute time you use and in our case our task runs so fast I am not sure we will even break out of the free tier with all the traffic we get. You could run an entire site with no server instances provisioned which is cool. In reality I think as the app grew it would be hard to manage as separate lambda functions and you would benefit greatly from a proper framework like Spring, but for something very small and light this seems super cool. The other neat thing about Lambda is the wide language support you can use, so I wrote my Lambda in Java and my boss just made a Lambda to do some logging that was written in Node. It is a super cool concept worth checking out.

MacOS Sierra massive slowdown in Java networking

I upgraded to MacOS Sierra, and have really been enjoying the shared clipboard. I haven’t really noticed any other new features that impact my day to day development, however I would advise Java developers to avoid it for the near future. I have searched and searched and I wasn’t coming up with any results. Then I found this blog post. This is definitely part of the problem. I made the host file changes and got a slight boost, but not enough to explain the whole thing.

First our original application is a monolithic Spring 4.2 app running in Tomcat. On my MacBook Pro it was taking 21-25 seconds to launch. After going to Sierra it started taking 75 seconds. Once I did the host file fix in the blog post above it started launching in 59 seconds. Still much worse than before.

Another Spring Boot micro service we have that does a lot of external api calls and also communicates through Amazon SQS would previously launch in 11 seconds on my laptop and now takes 141 seconds (150 prior to the fix outlined above). Even worse the messages to and from SQS and the third party API’s are painfully slow, sometimes taking 30 seconds or more to go through when previously they were almost instantaneous.

I am still searching for a fix for the issue, but it is practically unusable. I am debating if I am going to roll back to El Capitan, but at this point I would recommend people hold off on upgrading until there is a good understanding of what the slowdown is and how to fix it. Java itself when not hitting the network seems as fast as ever.

JHipster

I was reading the Spring Blog the other day and I came across this story. I was intrigued because I found the name funny so I read the post and watched the embedded youtube video and was completely blown away. Take all the excitement I had for Spring Boot after SpringOne and multiply it by 10. Not only does this build on top of Spring Boot it integrates in all the trendy front end technologies that are in use today. All the pain of bootstrapping and setting up a full on website is taken away while they do all the work for you.

JHipster is built on Spring Boot, Spring Security, Node.js, Angular.js, and Yeoman. Basically it manages to boil down every trendy front end technology with every trendy back end technology and do all the integration for you so you can start ripping code. They support Maven and Gradle as well as Grunt or Gulp. I admit I had never really heard of Yeoman or looked into it, but it is amazing. You can really automate a ton of your repetitive tasks with it so you can focus on solving the real problems you are facing. This project seems like a startup companies dream since all that monotonous configuration can just be skipped and you can focus on getting your application up and running and just out there.

This also fits in with my themes for the year where I wanted to spend more time working with Spring Boot as well as learning Angular and now I can all in the context of trying to build a small project under JHipster. Anyway the technology looks amazing and I would encourage everyone to give it a look and see what you think. Oh and a pro-tip if you are a non-hipster like myself running windows, when you do yo jhipster to generate your app, do it from inside of your git-bash window as if you use a normal windows cmd prompt it seems to fail in the course of generating the app.

Code Coverage

In my current position one of the metrics we track is code coverage for our unit tests. When I started at the company we were using JUnit with Mockito and JaCoCo. This was a pretty good setup we got good coverage reports and Mockito makes the testing writing much easier.

One of the limitations of Mockito is that you can’t mock private methods or static methods. This presented an issue for us in reaching our desired level of coverage. We initially worked around some of the private method issues using reflection, but it wasn’t always ideal. The decision was made to use PowerMock. PowerMock solved all of our Mockito issues immediately. It was compatible with Mockito but gave us some new powerful features to allow us to get much better unit test coverage. Then we ran our Jacoco reports and found that the reporting no longer worked. Due to the way PowerMock uses byte code manipulation in order to mock static methods it is not compatible with JaCoCo and there is no plan for them to support measuring that.

So we figured no big deal and switched to Cobertura. The first problem with this change is that Cobertura 2.0.3 has a regression in it so it won’t report coverage with Powermock. We figured no big deal we will run the 1.9.4.1 release of it until they release a bug fix so we can update. Unfortunately the update has never come. You go to the roadmap for the site and you see it hasn’t been updated since November 7, 2013. There appears to be very little activity on the project, and we haven’t seen an update in 2 years. I see work going on in the github repository but there seems to be no attempt and doing any maintenance or fixing the issues for the existing users, and I can’t get a feel for when the 2.1 release is ever going to come out. A second issue is that the current version doesn’t support Java 8 and I would like to update to Java 8 in the very near future. At what point when dealing with open source software do you say the project is either dead or too inactive for us to rely on for business needs?

Cut to last week I was updating some libraries in the project and I wanted to upgrade from PowerMock 1.5.5 to PowerMock 1.6.1 and my coverage reports went to 0. So it seems our old version of Cobertura can’t handle the latest PowerMock. I did a test with Atlassian Clover and our coverage reports worked perfect and looked better than anything I have ever seen for a report. At that point I decided I had reached my breaking point with Cobertura and put in a request that we move to clover and buy some server licenses and work and in the meantime while waiting for approval I had to settle for PowerMock 1.5.6 until we can get approval to buy Clover licenses.

Going forward when someone suggests a new tool to fix an issue that we are having, I have to say that I am going to be looking into other things that tool drags along with it as I don’t want to be in the situation again where we are trading one problem for another.