在第一次序列化后配置 ObjecMapper 空序列化没有效果

Configuring ObjecMapper null serialization after first serialization does not have effect

在使用 ObjectMapper 进行一些实验时偶然发现了这种行为。请参阅下面的 Junit5 测试用例以及那些在评论中为我打印的内容。

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}

    }

}

最后一个both()是我想知道的。 ObjectMapper第一次序列化后忽略包含指令是正常功能吗?

默认情况下 Jackson 为每个 POJO class 创建 BeanSerializer 个实例。它是在需要时按需创建的,并且 已缓存 。所以它的配置取决于 ObjectMapper 的当前状态,如果你改变 ObjectMapper 你需要清除缓存:

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

强制ObjectMapper创建BeanSerializer的新实例。

查看 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.

cachedSerializersCount方法:

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)

最好的解决方案可能是创建 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()));
    }
}