第一次序列化后配置ObjecMapper空序列化无效

问题描述

使用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}

    }

}

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

解决方法

默认情况下,Jackson为每个POJO类创建BeanSerializer实例。它是在需要时按需创建的,并缓存。因此,其配置取决于ObjectMapper的当前状态,如果更改ObjectMapper,则需要清除缓存:

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

强制ObjectMapper创建BeanSerializer的新实例。

看看BeanSerializerFactory的文档:

...
最后,由于所有缓存均由序列化程序提供程序处理 (不是工厂)并且没有可配置性,该工厂是 无状态的。这意味着可以使用全局单例实例。

cachedSerializersCount方法:

可用于确定此序列化器数量的方法 provider当前正在缓存(如果已缓存:默认) 实现的确)确切的数量取决于哪种序列化器 被缓存默认实现会缓存所有序列化程序,包括 渴望建造的(为了获得最佳访问速度)

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