Tuesday, August 13, 2013

On Jackson 2.2

Here's another thing I need to write about, from my "todo bloklog" (blog backlog): overview of Jackson 2.2 release.
As usual, official 2.2 release notes are worth checking out for more detailed listing.

1. Overview

Jackson 2.2.0 was released in April, 2013 -- that is, four months ago -- and the latest patch version currently available is 2.2.2. It has proven a nice, stable release, and is currently used by frameworks such as DropWizard (my current favorite Java service platform). This is also the current stable version, as the development for 2.3 is not yet complete.

As opposed to earlier releases (2.0 major, 2.1 minor) which overflowed with new functionality, focus with 2.2 was to really stabilize functionality and close as many open bugs as possible; especially ones related to new 2.x functionality.
Related to this, we wanted to improve parity (coverage of features to different parts; that is, that both serialization and deserialization support things; that Map/Node/POJO handling would be as similar as possible).

2. Enhancements to serializer, deserializer processing

One problem area, with respect to writing custom handlers for structured non-POJO types (esp. container types: arrays, Collections, Maps), was that BeanSerializerModifier and BeanDeserializerModifier handlers could only be used for POJO types.

But custom handling is needed for container types too; and especially so when adding support for third-party libraries like Trove, Guava and HPPC. 2.2 extended these interfaces to allow post-processing serializers/deserializers for all types (also including scalar types).

Ability to post-process (de)serializers of all types should reduce the need for writing custom (de)serializers from scratch: it is possible -- for example -- to take the default (de)serializer, and use post-processor to create (de)serializer that delegates to the standard version for certain cases, or for certain part of processing.

3. Converters

The biggest new feature was adding annotation-based support for adding things called "Converters". It can be seen as sort of further extension for the idea that one should be able to refine handling with small(er) component, instead of having to write custom handlers from scratch.

The basic idea is simple: to serialize custom types (that Jackson would not know how to handle correctly) one can write converters that know how to take a custom type and convert it into an intermediate object that Jackson already knows how to serialize. This intermediate form could be simple java.util.Map or JsonNode (tree model), or even just another more traditional POJO.

And for deserialization, do the reverse: let Jackson deserialize JSON into this intermediate type; and call converter to get to the custom type.

Typically you will write one or two converters (one if you just need converter for either serialization or deserialization; two if both); and then either annotate the type that needs converter(s); or property of that type that needs converter(s):

public class Point {
private int x, y;
public MyPoint(int x, int y) {
this.x = x;
this.y = y;
public int x() { return x; }
public int y() { return y; }

class SerializationConverter extends StdConverter<ConvertingBean, int[]> {
public int[] convert(MyPoint p) {
return new int[] { p.x(), p.y() };
// similarly for DeserializationConverter: StdConverter is convenient base class

This feature was inspired by similar concept in JAXB, and should have been included a long time ago (actually, 2.1 already added internal support for converters; 2.2 just added annotation and connected the dots).
One thing worth noting regarding above is that use of StdConverter is strongly recommended; although you may directly implement Converter there is usually little need. Also note that although example associated converters directly with the type, you can also add them to property definition; this can be useful when dealing with third-party types (although you can also use mix-in annotations for those cases).

4. Android

One "unusual" area for improvements was work to try to make Jackson run better on Android platform. Android has its set of quirks; and although Jackson was already working well from functionality perspective, there were obvious performance problems. This was especially true for data-binding, where initial startup overhead has been problematic.

One simple improvement was elimination of file VERSION.txt. While it seemed harmless enough thing for J2SE, Android's package loader has surprising overhead when loading resources from within a jar -- at least on some versions, contents of jar are retained in memory basically DOUBLING amount of memory needed. 2.2 replaced text-file based version discovery with simple class generation (as part of build, that is, static source generation).

Version 2.2 also contained significant amount of internal refactorings, to try to reduce startup overhead, by both simplifying set up of (de)serializers, and to try to improve lazy-loading aspects.
One challenge, however, is that we still do not have a good set of benchmarks to actually verify effects of these changes. So while the intent was to improve startup performance, we do not have solid numbers to report, yet.

On plus side, there is some on-going work to do more performance measurements; and I hope to write more about these efforts once related work is made public (it is not yet; I am not driving these efforts, but have helped).

5. JAX-RS: additional caching

Another area of performance improvements was that of JAX-RS provider. Earlier versions did reuse internal `ObjectMapper`, but had to do more per-call annotation processing. 2.2 added simple caching of results of annotation introspection, and should help reduce overhead.

One other important change was structural: before 2.2, there were multiple separate github projects (three; one for JSON, another for Smile, third for XML). With 2.2 we now have a single Github project, jackson-jaxrs-providers, with multiple Maven sub-projects that share code via a base package. This should simplify development, and reduce likelihood of getting cut'n paste errors.

6. AfterBurner becomes Production Ready

One more big milestone concerned Afterburner module (what is it? Check out this earlier entry). With a little help from my friends (special thanks to Steven Schlansker for his significant contributions!), all known issues were addressed and new checks added, such that we can now consider Afterburner production ready.

Given that use of Afterburner can give you 30-50% boost in throughput, when using data-binding, it might be good time to check it out.

blog comments powered by Disqus

Last posts

Sponsored By

Related Blogs

(by Author (topics))

Powered By

About me

  • I am known as Cowtowncoder
  • Contact me at@yahoo.com
Check my profile to learn more.