【问题标题】:Jackson: choose children class for deserialization depending of field existenceJackson:根据字段存在选择子类进行反序列化
【发布时间】:2017-02-20 15:16:02
【问题描述】:

我有以下型号:

public abstract class A {
    String commonField;
}

public class B extends A {    
}

public class C extends A {
    String customField;
}

如何根据是否存在“customField”字段来判断选择类(B 或 C)?

{ "commonField" : "..."} --> B instance

{ "commonField" : "...", "customField" : null} --> B instance

{ "commonField" : "...", "customField" : "..."} --> C instance

【问题讨论】:

    标签: java json jackson deserialization json-deserialization


    【解决方案1】:

    试试这个会有什么帮助

    ObjectMapper mapper = new ObjectMapper();
    
    String json = "{ \"commonField\" : \"...\", \"customField\"}";
    
    JsonNode jsonNode = mapper.readTree( json );
    
    A a; // class a
    
    if(jsonNode.has( "customField" )) {
    
        a = mapper.convertValue( jsonNode, C.class );           
    } else {
    
        a = mapper.convertValue( jsonNode, B.class );
    }
    

    【讨论】:

      【解决方案2】:

      我发现反序列化为 Map() 并迭代密钥非常简单,尤其是使用 Jackson API

      ObjectMapper mapper = new ObjectMapper();
      Map<String, String> map = mapper.readValue(jsonString, Map.class);
      for(String key : map.keySet)
      {
          if(key.equals("customField")
          {
              // do your stuff
          }
      }
      

      【讨论】:

      • 这太棒了。只需根据对象中的字段将一个字段反序列化为其子类,这是一种聪明的方法!
      • @Luminaire 很高兴为您服务。如果这成为标准,请考虑将“键”(字符串文字)保留在枚举中,以确保安全和安心。从长远来看会帮助你
      【解决方案3】:

      您可以为您的案例编写自己的反序列化程序,并在 ObjectMapper 中使用附加模块或在 A 上使用 @JsonDeserialize 注释进行注册。

      例如:

      public class ADeserializer extends StdDeserializer<A> {
          public ADeserializer() {
              super(A.class);
          }
      
          @Override
          public A deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
              JsonNode node = p.readValueAsTree();
              JsonNode customField = node.findValue("customField");
              A result;
              if (customField != null && !customField.isNull()) {
                  result = new C();
                  ((C)result).customField = customField.asText();
              } else {
                  result = new B();
              }
              result.commonField = node.findValue("commonField").asText();
              return result;
          }
      }
      

      并与新模块注册一起使用:

      @Test
      public void test() throws Exception {
          ObjectMapper mapper = new ObjectMapper();
          SimpleModule module = new SimpleModule();
          module.addDeserializer(A.class, new ADeserializer());
          mapper.registerModule(module);
      
          String jsonB = "{\"commonField\" : \"value\"}";
          Assert.assertTrue(mapper.readValue(jsonB, A.class) instanceof B);
          String jsonBNull = "{\"commonField\" : \"value\", \"customField\" : null}";
          Assert.assertTrue(mapper.readValue(jsonBNull, A.class) instanceof B);
          String jsonC = "{\"commonField\" : \"value\", \"customField\" : \"anotherValue\"}";
          Assert.assertTrue(mapper.readValue(jsonC, A.class) instanceof C);
      }
      

      【讨论】:

        猜你喜欢
        • 2020-05-01
        • 2016-08-05
        • 1970-01-01
        • 2016-05-27
        • 1970-01-01
        • 2014-10-06
        • 1970-01-01
        • 1970-01-01
        • 2021-12-13
        相关资源
        最近更新 更多