Deserialize external library classes with a builder method as a constructor

Viewed 1122

I have a class like this:

class MyClass {
    CustomList<String> list = ListUtils.createCustomList();
}

Where interface CustomList implements java.util.List so it cannot be deserialized with a constructor. Instead there is a class ListUtils which creates an implementation instance. Both the interface and the utility class are in an external library so I can't annotate them.

How can I tell Jackson that when encountering CustomList it should invoke ListUtils.createCustomList() instead of a constructor? Is there a mixin configuration, a mapping I can specify from type to construction method, or a custom deserializer I need to write?

1 Answers

You have 2 issues here, the first of which is how to tell Jackson to use a static method of another class ListUtils to create an instance of CustomList class. There is @JsonCreator that you could use on a static method of CustomList or through a mix in. Unfortunately, you can't use that on ListUtils. There is a an open issue for that.

Until the above request is implemented / released you have to create a custom deserializer. A skeleton implementation of such a deserializer would look something like this:

class ListDeserializer extends JsonDeserializer<CustomList> {
    @Override
    public CustomList deserialize(JsonParser p, DeserializationContext c) throws IOException {
        return ListUtils.createCustomList();
    }
}

Extend this method with other initialization steps, e.g. to parse elements with JsonParser and add them to the list before returning it. See an example here. You can specify this deserializer to be used without any annotations on the ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(CustomList.class, new ListDeserializer());
mapper.registerModule(module);
Related