Jackson:根据字段存在选择 children class 进行反序列化
Jackson: choose children class for deserialization depending of field existence
我有以下型号:
public abstract class A {
String commonField;
}
public class B extends A {
}
public class C extends A {
String customField;
}
如何根据存在的 'customField' 字段判断选择 class(B 或 C)?
{ "commonField" : "..."} --> B instance
{ "commonField" : "...", "customField" : null} --> B instance
{ "commonField" : "...", "customField" : "..."} --> C instance
您可以为您的案例编写自己的反序列化器,并在 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);
}
我发现反序列化为 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
}
}
试试看这个会有什么帮助
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 );
}
我有以下型号:
public abstract class A {
String commonField;
}
public class B extends A {
}
public class C extends A {
String customField;
}
如何根据存在的 'customField' 字段判断选择 class(B 或 C)?
{ "commonField" : "..."} --> B instance
{ "commonField" : "...", "customField" : null} --> B instance
{ "commonField" : "...", "customField" : "..."} --> C instance
您可以为您的案例编写自己的反序列化器,并在 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);
}
我发现反序列化为 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
}
}
试试看这个会有什么帮助
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 );
}