有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

已配置Jackson ObjectMapper的java意外序列化行为

我正在使用Jackson 2.10.5将同一java.util.Date对象序列化三次

  1. 第一次,用基本的Jackson ObjectMapper。我看到时间戳了
  2. 然后配置相同的ObjectMapper,并重写。我得到了同样的结果
  3. 然后我构造一个新的ObjectMapper,用同样的方式配置它。我得到了一个不同的结果,JSON列表中的类名和时间戳

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

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

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

[编辑:我应该提到,这个用例是作为Jersey的JSON提供程序。我有一种在启动时生成和配置ObjectMapper的方法,但是(in)配置每次写入的能力仅适用于上面的测试代码。]

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]

共 (1) 个答案

  1. # 1 楼答案

    阅读文档,即^{}的javadoc,上面写着粗体我的亮点)

    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:

    • 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.

    • 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.