Gili Gili - 6 months ago 38
JSON Question

Jackson + Builder Pattern?

I'd like Jackson to deserialize a class with the following constructor:

public Clinic(String name, Address address)

Deserializing the first argument is easy. The problem is that Address is defined as:

public class Address {
private Address(Map<LocationType, String> components)

public static class Builder {
public Builder setCity(String value);
public Builder setCountry(String value);
public Address create();

and is constructed like this:
new Address.Builder().setCity("foo").setCountry("bar").create();

Is there a way to get key-value pairs from Jackson in order to construct the Address myself? Alternatively, is there a way to get Jackson to use the Builder class itself?


I ended up implementing this using the @JsonDeserialize as follows:

@JsonDeserialize(using = JacksonDeserializer.class)
public class Address

static class JacksonDeserializer extends JsonDeserializer<Address>
    public Address deserialize(JsonParser parser, DeserializationContext context)
        throws IOException, JsonProcessingException
        JsonToken token = parser.getCurrentToken();
        if (token != JsonToken.START_OBJECT)
            throw new JsonMappingException("Expected START_OBJECT: " + token, parser.getCurrentLocation());
        token = parser.nextToken();
        Builder result = new Builder();
        while (token != JsonToken.END_OBJECT)
            if (token != JsonToken.FIELD_NAME)
                throw new JsonMappingException("Expected FIELD_NAME: " + token, parser.getCurrentLocation());
            LocationType key = LocationType.valueOf(parser.getText());

            token = parser.nextToken();
            if (token != JsonToken.VALUE_STRING)
                throw new JsonMappingException("Expected VALUE_STRING: " + token, parser.getCurrentLocation());
            String value = parser.getText();

            // Our Builder allows passing key-value pairs
            // alongside the normal setter methods.
            result.put(key, value);
            token = parser.nextToken();
        return result.create();