【问题标题】:How to trigger calls to .serializeWithType() of a class implementing JsonSerializable in Jackson?如何触发对杰克逊中实现 JsonSerializable 的类的 .serializeWithType() 的调用?
【发布时间】:2014-12-27 15:12:03
【问题描述】:

这是 Jackson 2.2.x。

我有一个实现JsonSerializable 的类;这个接口有两种方法可以实现,serialize()serializeWithType()

我想测试这个类的{de,}序列化,我可以很容易地触发对serialize()的调用;但是,serializeWithType() 不是。

javadoc for this latter method 表示调用了这个方法

[...] 当附加类型信息预计将包含在序列化中时,以供反序列化使用。

我只是不明白这是什么意思......

如何设置测试环境以便调用此方法?注意,要序列化的 JSON 可以是除 object 以外的任何类型(即 boolean、number、string、array 都是有效类型)。

【问题讨论】:

    标签: java serialization jackson json-deserialization


    【解决方案1】:

    当你想使用多态时使用此方法

    public class A {
        ...
    }
    
    public class B extends A {
        ...
    }
    
    public class C extends A {
        ...
    }
    

    如果您序列化 C 的实例,然后尝试反序列化生成的 json,但只知道它是 A 的子类型:

    final ObjectMapper objectMapper = new ObjectMapper();
    final String json = objectMapper.writeValueAsString(new C());
    final A deserialized = objectMapper.readValue(json, A.class);
    

    您需要在生成的 JSON 中存储一些内容以保持序列化对象的真实类型。

    这可以通过在您的班级上使用@JsonTypeInfo 或通过在您的ObjectMapper 上调用enableDefaultTyping 来启用。

    这是一个使用 JUnit 和 Mockito 的示例测试用例

    import com.fasterxml.jackson.databind.JsonSerializable;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.junit.Test;
    
    import static org.mockito.Matchers.any;
    import static org.mockito.Mockito.mock;
    import static org.mockito.Mockito.times;
    import static org.mockito.Mockito.verify;
    
    public class SerializeWithTypeTest {
    
        private JsonSerializable serializable = mock(JsonSerializable.class);
    
        @Test
        public void shouldCallSerializeWithType() throws Exception {
            final ObjectMapper objectMapper = new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    
            objectMapper.writeValueAsString(serializable);
    
            // make sure serializeWithType is called once
            verify(serializable, times(1)).serializeWithType(any(), any(), any());
    
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      Jackson 2 is completely incompatible with Jackson 1JsonSerializableWithType(现已弃用且无法使用)是 Jackson 1 的接口,导致 Jackson 2 中出现 serializeWithType()

      serializeWithType() 在预期包含其他类型信息时被调用,这意味着当使用多态性时,注释 (JsonTypeInfo) 正在为反序列化委托指定类 property。然后将使用TypeSerializer 中的附加类型信息调用此方法,可以使用类型前缀编写:

      /* (.., .., TypeSerializer typeSer) */ {
          typeSer.writeTypePrefixForScalar(.., .., ThisClass.class);
      }

      通过使用@JsonTypeInfo 注释类,您将能够使用类型信息指定序列化:

      @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
              include = As.WRAPPER_OBJECT,
              property = "type")
      @JsonSubTypes({
              @Type(name = "typeint", value = MyInt.class),
              @Type(name = "typefloat", value = MyFloat.class)
      })
      public interface MyNumber {}
      
      @JsonTypeName("typeint")
      public MyInt implements MyNumber {}
      
      @JsonTypeName("typefloat")
      public MyFloat implements MyNumber {}
      

      然后值typeinttypefloat 将在名为type 的属性中设置。当您反序列化MyNumber 时,它将基于多态性。 Thomas Maurel's answer 演示了一种直接的测试方法,将对象序列化为字符串并反序列化。

      【讨论】:

        【解决方案3】:

        尝试在您的班级上使用JsonTypeInfo 注释。它应该触发调用serializeWithType()。它用于存储有关多态类型所需的类型信息或链接抽象类型和匹配的具体实现。

        【讨论】:

          猜你喜欢
          • 2018-02-10
          • 1970-01-01
          • 2018-08-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多