Jackson: serialize non-initialized collection fiel

2019-07-15 05:12发布

I have a POJO with a field or property, containing collection of objects, something like this:

public class Box {

    public List<Items> items;

}

By default, value of items is null, and I do not want to initialize it with empty list.

Now, if I try to serialize it with Jackson, I get NullPointerException. Is there a simple way to make Jackson not break on such value and serialize it as an empty collection: [ ]?

Note. This class is just a simplified example. In reality, there are a hundred of classes and a number of fields with different names in each of them, which are occasionally set to null sometimes somewhere in the code, breaking serialization in runtime.

3条回答
Viruses.
2楼-- · 2019-07-15 05:47

Have you considered making this class a JavaBean? In that case, you would be able to give a default value in the getter:

public class Box {
    private List<Items> items;
    public List<Items> getItems() {
        if(null == items) {
            return Collections.emptyList();
        }
        return this.items;
    }
    //Setter here
}

This approach would prevent a lot of trouble related to Jackson's assumptions.

Update: Based on clarification... You could implement a custom serializer for the list type (and/or any other desired customization). Please note that :

public class ListSerializer extends JsonSerializer<List> {
    @Override
    public void serialize(List value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
            JsonProcessingException {

        if (null == value) {
            provider.defaultSerializeValue(new ArrayList<Object>(), jgen);
        } else {
            provider.defaultSerializeValue(value, jgen);
        }
    }
}

//Then your code could set the serializer on the object mapper as follows:
objectMapper.addSerializer(List.class, new ListSerializer());

Repeat for all such customization.

Code was inspired by this article: http://www.baeldung.com/jackson-custom-serialization

查看更多
Anthone
3楼-- · 2019-07-15 05:54

The easiest way to solve this problem is by initializing the List in a default constructor:

public class Box {

    private List<Item> items;

    public Box() {
        items = new ArrayList<>();
    }

    public List<Item> getItems() {
        return items;
    }

    public setItems(List<Item> items) {
        this.items = items;
    }

    public void addItem(Item item) {
        items.add(item);
    }
}
查看更多
疯言疯语
4楼-- · 2019-07-15 05:58

If you do not want to change the contract of your POJO class, think about the possibility to define custom Jackson serializer / deserializer which extend JsonSerializer<T> and JsonDeserializer<T> respectively. E.g.:

 public class CountryDeserializer extends JsonDeserializer<CountryCode> {
     @Override
     public CountryCode deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException {
         return CountryCode.getByCode(jp.getText());
     }
 }

and then

 @JsonDeserialize(using=CountryDeserializer.class)
 private CountryCode country;

You can check whether your field is null and act accordingly, in both directions (serialization / deserialization).

查看更多
登录 后发表回答