使用已配置的Jackson ObjectMapper发生意外的序列化行为 [英] Unexpected serialization behavior with configured Jackson ObjectMapper

查看:266
本文介绍了使用已配置的Jackson ObjectMapper发生意外的序列化行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Jackson 2.10.5序列化相同的java.util.Date对象3次.

I am using Jackson 2.10.5 to serialize the same java.util.Date object three times.

  1. 第一次使用基本的Jackson ObjectMapper.我看到了时间戳.
  2. 然后我配置相同的ObjectMapper,然后重写.我得到相同的结果.
  3. 然后我构造一个新的ObjectMapper,以相同的方式配置它.我得到了不同的结果,即JSON列表中的类名和时间戳.
  1. The first time, with a basic Jackson ObjectMapper. I see the timestamp.
  2. Then I configure the same ObjectMapper, and rewrite. I get the same result.
  3. Then I construct a new ObjectMapper, configure it the same way. I get a different result, the class name and the timestamp in a JSON list.

该配置旨在告知ObjectMapper将除java.util.Date 之外的每个对象的类名称作为JSON属性包含.

The configuration is intended to tell the ObjectMapper to include the class name of every object except java.util.Date as a JSON property.

所以我有两个问题.首先是为什么在第三种情况下日期对象的序列化有所不同?有关以不同方式使用PolymorphicTypeMapper的任何建议,将不胜感激.

So I have two questions. The first is why is the date object serialized differently in the third case? Any advice on using the PolymorphicTypeMapper differently would be appreciated.

第二个是为什么第一个和第二个相同的原因(是因为对象映射器具有缓存(哎呀!)吗?).

The second is why the first and second are the same (is it because the Object mapper has a cache (ouch!)?).

private PolymorphicTypeValidator getPTV() {
    return BasicPolymorphicTypeValidator.builder()
            .denyForExactBaseType(Date.class)
            .build();
}


@Test
public void serializationTest() {
    try {
        Date now = new Date();

        // Create an object mapper and serialize the date
        ObjectMapper om = new ObjectMapper();
        String serialized1 = om.writeValueAsString(now); // result: 1605744866827

        om.activateDefaultTypingAsProperty(getPTV(), ObjectMapper.DefaultTyping.EVERYTHING, "@class");
        String serialized2 = om.writeValueAsString(now); // result: 1605744866827

        ObjectMapper om2 = new ObjectMapper();
        om2.activateDefaultTypingAsProperty(getPTV(), ObjectMapper.DefaultTyping.EVERYTHING, "@class");
        String serialized3 = om2.writeValueAsString(now); // result: ["java.util.Date",1605744866827]

        Logger.getLogger(SerializationTest.class).info(serialized1);
        Logger.getLogger(SerializationTest.class).info(serialized2);
        Logger.getLogger(SerializationTest.class).info(serialized3);

        Assert.assertEquals("Unexpected change in serialization 1-2", serialized1, serialized2);
        Assert.assertEquals("Unexpected change in serialization 1-3", serialized1, serialized3);

    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
}

这是输出:

INFO  2020-11-18 16:14:27,065 [main] <> test.SerializationTest : 1605744866827
INFO  2020-11-18 16:14:27,066 [main] <> test.SerializationTest : 1605744866827
INFO  2020-11-18 16:14:27,066 [main] <> test.SerializationTest : ["java.util.Date",1605744866827]

org.junit.ComparisonFailure: Unexpected change in serialization 1-3 
Expected :1605744866827
Actual   :["java.util.Date",1605744866827]

推荐答案

阅读文档,即

Read the documentation, i.e. the javadoc of ObjectMapper, which says (bold highlights by me):

映射器实例是完全线程安全的,前提是实例 ALL配置在任何读取或写入调用之前发生.如果首次使用后修改了映射器的配置,则更改可能会生效或可能不会生效,并且配置调用自身可能会失败.如果需要使用其他配置,则有两种主要可能性:

Mapper instances are fully thread-safe provided that ALL configuration of the instance occurs before ANY read or write calls. If configuration of a mapper is modified after first usage, changes may or may not take effect, and configuration calls themselves may fail. If you need to use different configuration, you have two main possibilities:

  • 构造并使用ObjectReader进行阅读,使用ObjectWriter进行书写.两种类型都是完全不变的,您可以使用ObjectMapper的工厂方法或读取器/写入器本身自由创建具有不同配置的新实例.构造新的ObjectReaderObjectWriter的操作非常轻巧,因此通常需要根据需要在每次调用的基础上创建它们,以配置诸如JSON的可选缩进之类的内容.

  • Construct and use ObjectReader for reading, ObjectWriter for writing. Both types are fully immutable and you can freely create new instances with different configuration using either factory methods of ObjectMapper, or readers/writers themselves. Construction of new ObjectReaders and ObjectWriters is a very light-weight operation so it is usually appropriate to create these on per-call basis, as needed, for configuring things like optional indentation of JSON.

如果通过ObjectReaderObjectWriter无法获得特定类型的可配置性,则可能需要使用多个ObjectMapper (例如:您不能更改混合-in即时注释;或者,一组自定义(反)序列化器).为了帮助使用此方法,您可能需要使用方法copy(),该方法将创建具有特定配置的映射器的副本,并允许在使用复制实例之前对其进行配置.请注意,copy()操作与构造一个新的ObjectMapper实例一样昂贵:如果可能的话,如果打算将它们用于多个操作,则仍应合并并重用映射器.

If the specific kind of configurability is not available via ObjectReader and ObjectWriter, you may need to use multiple ObjectMapper instead (for example: you can not change mix-in annotations on-the-fly; or, set of custom (de)serializers). To help with this usage, you may want to use method copy() which creates a clone of the mapper with specific configuration, and allows configuration of the copied instance before it gets used. Note that copy() operation is as expensive as constructing a new ObjectMapper instance: if possible, you should still pool and reuse mappers if you intend to use them for multiple operations.

这篇关于使用已配置的Jackson ObjectMapper发生意外的序列化行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆