Rescuing empty JSON arrays in Micronaut

Rescuing empty JSON arrays in Micronaut

A while back I rewrote the Sparkled backend with Micronaut. The backend was a hodge-podge of libraries that worked well enough, but had some nasty glue code that I wasn't too proud of.

Micronaut is a Spring-like framework from the creators of Grails. Micronaut's raison d'être is to reduce the startup time and memory footprints of microservices by doing some heavy lifting at compile time instead of reflecting at runtime.

O [], []! Wherefore art thou []?

The Micronaut rewrite went great and everything's been running smoothly, but I came across a weird issue last night. When I hit an API endpoint that has an empty array, the array is omitted from the JSON response.

This isn't ideal. My frontend code is built on the assumption that the array will always be provided, which is reasonable since I have full control over the API.

I tried breakpointing the endpoint and serialising the object out using a plain Jackson mapper. Lo and behold, the empty array was there. Time to do some Jackson API sleuthing...

Where are the docs at?

Jackson is a great library, but its documentation really isn't great. The GitHub readme has dozens and dozens of links, with one documentation link tucked away towards the end. Hitting that link takes you to another markdown file with some third-party tutorials and a link to the jackson-docs repository.

Finally I found the Finding Javadoc page, which tells me to construct my own URL to get access to the Javadoc for a given Jackson version. That's fine, but it's quicker for me to just look at the source via IntelliJ.

The solution

After looking through the docs and going on a couple of wild goose chases, I ended up setting a breakpoint on the ObjectMapperFactory Jackson class. I hit my endpoint and then stepped through the huge objectMapper method.

I stepped through each line, and used the local mapper object to serialise an empty array at every step. This revealed the culprit pretty quickly:

objectMapper.setSerializationInclusion(include);

By default, Micronaut sets the serializationInclusion value to JsonInclude.NON_EMPTY, which omits empty objects/arrays from JSON to save space.

To remedy this, I changed the value to JsonInclude.ALWAYS in application.yml:

jackson:
  serializationInclusion: ALWAYS # Include empty arrays in JSON output