Monday, June 24, 2013

Mixin it up Jackson style

We have already discovered the goodness of Jackson for vending out JSON data in a JAX-RS setup. In many cases, our domain objects have references to other domain objects that are not under our control (e.g. classes from third-party JARs). We can easily add annotations to our domain objects to indicate which fields to ignore, but what do we do for the third party objects? One could choose to write custom bean serializers, but that is pretty onerous on the part of the user and one that requires higher maintenance since it is away from the original class. Here is where Jackson Mixins comes to the rescue.

The central idea here is to use annotations for configuration without having to embed them in the upstream code. For one, embedded them upstream may not be possible - for others, they might not like to use non-standard annotations in their code. This is where the mixin annotations position themselves. Snip from the fasterxml.com site:
That is, you can:
  1. Define that annotations of a mix-in class (or interface)
  2. will be used with a target class (or interface) such that it appears
  3. as if the target class had all annotations that the mix-in class has (for purposes of configuring serialization / deserialization)
You can think of it as kind of aspect-oriented way of adding more annotations during runtime, to augment statically defined ones.
Let's see it in action:
Say I have a third party class SpecialObject.java as:
public class SpecialObject {
    private String name;
    private Integer id;
    private Date date;
}
where I wish to not serialize its id property. I define a mixin class (interface) as SpecialObjectMixin.java that only exposes the name and date properties.
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonProperty;
@JsonAutoDetect(getterVisibility = Visibility.NONE)
public interface SpecialObjectMixin {
    @JsonProperty
    public String getName();
    @JsonProperty
    public Date getDate();
}

As we know, Jackson serialization works by means of public getters by default. You can choose to have it work with field as well, but for sake of simplicity, let's assume getter route. The @JsonAutoDetect annotation when configured with getterVisibility none indicates to the Jackson serializer that none of the getters from the target class need to be fired which basically mutes the effects of the target class - which may infact have several properties. Now, we are free to serialize as we deem necessary in our usage without bothering the upstream class about defining a cleaner public view. Since we have defined it as an interface, we can just mention the method signatures and annotate them with @JsonProperty. Jackson ensures that values from the target class are used for serialization. For gluing these two together in a Spring world, one can define a MixinSetter as a BeanFactoryPostProcessor that sets up the mixin class to target class association in the serialization and deserialization configurations. I have a sample setup where you could see this in action.

References:

No comments:

Post a Comment