Configuring ObjecMapper null serialization after first serialization does not have effect

强颜欢笑 提交于 2021-01-28 08:40:24

问题


Stumbled on this behavior when making some experiments with ObjectMapper. See Junit5 test cases below and what those print for me in comments.

class TestIt {

    private ObjectMapper om = new ObjectMapper();
    private TestClass testClass = new TestClass();

    @Getter @Setter
    public class TestClass {
        private final String value = LocalDate.now().toString();
        private String valueLeftNull;
    }
    
    @Test
    void defaultMapping() throws JsonProcessingException {
        System.out.println(om.writeValueAsString(testClass));
        // {"value":"2020-11-02","valueLeftNull":null}
    }

    @Test
    void nonNull() throws JsonProcessingException {
        om.setSerializationInclusion(Include.NON_NULL);
        System.out.println(om.writeValueAsString(testClass));
        // {"value":"2020-11-02"}
    }

    @Test
    void both() throws JsonProcessingException {
        System.out.println(om.writeValueAsString(testClass));
        om.setSerializationInclusion(Include.NON_NULL);
        System.out.println(om.writeValueAsString(testClass));
        System.out.println(om.writeValueAsString(new TestClass()));
        // {"value":"2020-11-02","valueLeftNull":null}
        // {"value":"2020-11-02","valueLeftNull":null}
        // {"value":"2020-11-02","valueLeftNull":null}

    }

}

The last one both() is what I am wondering. Is it normal functionality that ObjectMapper ignores the inclusion instruction after the first serialization?


回答1:


By default Jackson creates BeanSerializer instance for each POJO class. It is created on demand when is needed and cached. So it's configuration depends from current state of ObjectMapper and if you change ObjectMapper you need to clear cache:

((DefaultSerializerProvider) om.getSerializerProvider()).flushCachedSerializers();

to force ObjectMapper to create new instance of BeanSerializer.

Take a look at documentation for BeanSerializerFactory:

...
Finally, since all caching is handled by the serializer provider (not factory) and there is no configurability, this factory is stateless. This means that a global singleton instance can be used.

and cachedSerializersCount method:

Method that can be used to determine how many serializers this provider is caching currently (if it does caching: default implementation does) Exact count depends on what kind of serializers get cached; default implementation caches all serializers, including ones that are eagerly constructed (for optimal access speed)

Probably the best solution would be to create two instances of ObjectMapper:

class TestIt {

    private JsonMapper nonNullMapper = JsonMapper.builder()
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .build();
    private JsonMapper defaultMapper = JsonMapper.builder().build();
    private TestClass testClass = new TestClass();

    @Getter
    @Setter
    public static class TestClass {
        private final String value = LocalDate.now().toString();
        private String valueLeftNull;
    }

    void defaultMapping() throws JsonProcessingException {
        System.out.println(defaultMapper.writeValueAsString(testClass));
    }

    void nonNull() throws JsonProcessingException {
        System.out.println(nonNullMapper.writeValueAsString(testClass));
    }

    void both() throws JsonProcessingException {
        System.out.println(defaultMapper.writeValueAsString(testClass));
        System.out.println(nonNullMapper.writeValueAsString(testClass));
        System.out.println(nonNullMapper.writeValueAsString(new TestClass()));
    }
}


来源:https://stackoverflow.com/questions/64642641/configuring-objecmapper-null-serialization-after-first-serialization-does-not-ha

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