【问题标题】:Configuring ObjecMapper null serialization after first serialization does not have effect首次序列化后配置 ObjecMapper 空序列化无效
【发布时间】:2021-02-14 22:31:17
【问题描述】:

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

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第一次序列化后忽略包含指令是正常功能吗?

【问题讨论】:

    标签: java json serialization jackson jackson2


    【解决方案1】:

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

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

    强制ObjectMapper 创建BeanSerializer 的新实例。

    查看BeanSerializerFactory 的文档:

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

    cachedSerializersCount方法:

    可用于确定此序列化器数量的方法 提供者当前正在缓存(如果它缓存:默认 实现确实)确切的计数取决于什么样的序列化器 被缓存;默认实现缓存所有序列化程序,包括 急切构建的(以获得最佳访问速度)

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

    【讨论】:

    • 干得好。这不是任何真正的问题,而是让我思考为什么。 flushCachedSerializers() 工作。允许调用它有点令人困惑,但它对已经序列化一次的类没有任何作用。也许它可以在设置包含或抛出异常时使这个刷新。也许它没有这样做是有充分理由的。
    • @pirho,因为Jackson 引入了JsonMapper 和构建器模式,它可能是创建新ObjectMapper 的最佳方式。如果您需要不同的配置,则需要创建新实例。很简单,这样我们就可以避免这种情况。
    猜你喜欢
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多