Jackson global settings to deserialise array to custom list implementation

て烟熏妆下的殇ゞ 提交于 2021-02-08 21:42:23

问题


By default, Jackson is using java.util.ArrayList to deserialise a JSON array. Instead of this, I want to use a custom implementation. For example, Guava ImmutableList if value is present, or Collection.emptyList() if JSON array is empty or null.

I want to configure this globally for ObjectMapper. Is there an easy way to do this?

PS: My Jackson version is 2.9.7


回答1:


General solution is to use custom module. You can define classes you would like to use for collections. For Guava there is a Maven module:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-guava</artifactId>
    <version>x.y.z</version>
</dependency>

Now, you can register your new module:

ObjectMapper mapper = new ObjectMapper();
// register module with object mapper
mapper.registerModule(new GuavaModule());

Now, you can define in your POJO you want to have immutable implementation of the list.

class Pojo {

    private ImmutableList<Integer> ints;

    public ImmutableList<Integer> getInts() {
        return ints;
    }

    public void setInts(ImmutableList<Integer> ints) {
        this.ints = ints;
    }

    @Override
    public String toString() {
        return "Pojo{" +
                "ints=" + ints + " " + ints.getClass() + '}';
    }
}

and below example:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new GuavaModule());

String json = "{\"ints\":[1,2,3,4]}";

System.out.println(mapper.readValue(json, Pojo.class));

prints:

Pojo{ints=[1, 2, 3, 4] class com.google.common.collect.RegularImmutableList}

If you do not want to tie your POJO classes with List implementation you need to add some extra configuration using SimpleModule class. So, your POJO looks like below:

class Pojo {

    private List<Integer> ints;

    public List<Integer> getInts() {
        return ints;
    }

    public void setInts(List<Integer> ints) {
        this.ints = ints;
    }

    @Override
    public String toString() {
        return "Pojo{" +
                "ints=" + ints + " " + ints.getClass() + '}';
    }
}

and your example looks like this:

SimpleModule useImmutableList = new SimpleModule("UseImmutableList");
useImmutableList.addAbstractTypeMapping(List.class, ImmutableList.class);

GuavaModule module = new GuavaModule();

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.registerModule(useImmutableList);

String json = "{\"ints\":[1,2,3,4]}";

System.out.println(mapper.readValue(json, Pojo.class));

Above code prints:

Pojo{ints=[1, 2, 3, 4] class com.google.common.collect.RegularImmutableList}

When you remove extra SimpleModule above code prints:

Pojo{ints=[1, 2, 3, 4] class java.util.ArrayList}

I do not see any point to use Collections.emptyList() in case it is empty. Guava's module uses RegularImmutableList for not empty and empty arrays.

For converting null -> empty see this question:

  1. Jackson deserializer - change null collection to empty one

but I recommend to set it to empty in POJO like below:

private List<Integer> ints = Collections.emptyList();



回答2:


I don't think that easy way exists, because CollectionDeserializer create instance of collection before parse. So, for this purposes you need to create your custom deserializer.

But I'm not sure=))



来源:https://stackoverflow.com/questions/54255852/jackson-global-settings-to-deserialise-array-to-custom-list-implementation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!