假设我有以下格式的JSON:
{
"type" : "Foo"
"data" : {
"object" : {
"id" : "1"
"fizz" : "bizz"
...
},
"metadata" : {
...
},
"owner" : {
"name" : "John"
...
}
}
}我试图避免自定义反序列化器,并试图将上述JSON (称为Wrapper.java)反序列化为Java。"type“字段指示"object”反序列化(即。type = foo是指使用Foo.java反序列化"object“字段。(如果type = Bar,使用Bar.java反序列化对象字段)。元数据/所有者将始终使用简单的Jackson注释Java类对每个类进行反序列化。是否有一种使用注释来完成这一任务的方法?如果不是,如何使用自定义反序列化程序来完成此操作?
发布于 2017-05-23 01:22:23
只作说明的方法
或者,对于自定义反序列化方法,您可以为只使用注释的解决方案提供以下内容(类似于Spunc的回答中描述的解决方案,但使用type作为外部财产):
public abstract class AbstractData {
private Owner owner;
private Metadata metadata;
// Getters and setters
}public static final class FooData extends AbstractData {
private Foo object;
// Getters and setters
}public static final class BarData extends AbstractData {
private Bar object;
// Getters and setters
}public class Wrapper {
private String type;
@JsonTypeInfo(use = Id.NAME, property = "type", include = As.EXTERNAL_PROPERTY)
@JsonSubTypes(value = {
@JsonSubTypes.Type(value = FooData.class, name = "Foo"),
@JsonSubTypes.Type(value = BarData.class, name = "Bar")
})
private AbstractData data;
// Getters and setters
}在这种方法中,@JsonTypeInfo被设置为使用type作为外部财产来确定映射data属性的正确类。
可以将JSON文档反序列化如下:
ObjectMapper mapper = new ObjectMapper();
Wrapper wrapper = mapper.readValue(json, Wrapper.class); 发布于 2017-05-22 23:54:28
自定义反序列化方法
您可以使用检查type属性的自定义反序列化程序将object属性解析为最合适的类。
首先定义一个将由Foo和Bar类实现的接口:
public interface Model {
}public class Foo implements Model {
// Fields, getters and setters
}public class Bar implements Model {
// Fields, getters and setters
}然后定义Wrapper和Data类:
public class Wrapper {
private String type;
private Data data;
// Getters and setters
}public class Data {
@JsonDeserialize(using = ModelDeserializer.class)
private Model object;
private Metadata metadata;
private Owner owner;
// Getters and setters
}object字段使用@JsonDeserialize注释,指示将用于object属性的反序列化器。
反序列化器的定义如下:
public class ModelDeserializer extends JsonDeserializer<Model> {
@Override
public Model deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonMappingException {
// Get reference to ObjectCodec
ObjectCodec codec = jp.getCodec();
// Parse "object" node into Jackson's tree model
JsonNode node = codec.readTree(jp);
// Get value of the "type" property
String type = ((Wrapper) jp.getParsingContext().getParent()
.getCurrentValue()).getType();
// Check the "type" property and map "object" to the suitable class
switch (type) {
case "Foo":
return codec.treeToValue(node, Foo.class);
case "Bar":
return codec.treeToValue(node, Bar.class);
default:
throw new JsonMappingException(jp,
"Invalid value for the \"type\" property");
}
}
}可以将JSON文档反序列化如下:
ObjectMapper mapper = new ObjectMapper();
Wrapper wrapper = mapper.readValue(json, Wrapper.class); 或者,对于此自定义反序列化器,请考虑使用只作说明的方法。
发布于 2017-05-23 00:31:23
所有这些都可以通过注释来完成。
使用“元数据”和“所有者”等公共字段以及它们的getter/setter创建一个抽象超类。这个类需要用@JsonTypeInfo进行注释。看起来应该是:
@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "type")使用参数property = "type",您可以指定类标识符将在JSON文档中的字段类型下序列化。
类标识符的值可以用use指定。Id.CLASS使用完全限定的Java类名。您还可以使用Id.MINIMAL_CLASS,它是一个缩写的Java类名。若要拥有自己的标识符,请使用Id.NAME。在这种情况下,您需要声明以下子类型:
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Foo.class, name = "Foo"),
@JsonSubTypes.Type(value = Bar.class, name = "Bar")
})通过从抽象超类进行扩展来实现类Foo和Bar。
杰克逊的ObjectMapper将使用JSON文档的附加字段"type“进行序列化和反序列化。例如,当您将JSON字符串反序列化为超类引用时,它将属于适当的子类:
ObjectMapper om = new ObjectMapper();
AbstractBase x = om.readValue(json, AbstractBase.class);
// x will be instanceof Foo or Bar完整代码示例(我使用公共字段作为快捷方式,不需要编写getter/setter):
package test;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonSubTypes;
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Foo.class, name = "Foo"),
@JsonSubTypes.Type(value = Bar.class, name = "Bar")
})
public abstract class AbstractBase {
public MetaData metaData;
public Owner owner;
@Override
public String toString() {
return "metaData=" + metaData + "; owner=" + owner;
}
public static void main(String[] args) throws IOException {
// Common fields
Owner owner = new Owner();
owner.name = "Richard";
MetaData metaData = new MetaData();
metaData.data = "Some data";
// Foo
Foo foo = new Foo();
foo.owner = owner;
foo.metaData = metaData;
CustomObject customObject = new CustomObject();
customObject.id = 20l;
customObject.fizz = "Example";
Data data = new Data();
data.object = customObject;
foo.data = data;
System.out.println("Foo: " + foo);
// Bar
Bar bar = new Bar();
bar.owner = owner;
bar.metaData = metaData;
bar.data = "A String in Bar";
ObjectMapper om = new ObjectMapper();
// Test Foo:
String foojson = om.writeValueAsString(foo);
System.out.println(foojson);
AbstractBase fooDeserialised = om.readValue(foojson, AbstractBase.class);
System.out.println(fooDeserialised);
// Test Bar:
String barjson = om.writeValueAsString(bar);
System.out.println(barjson);
AbstractBase barDeserialised = om.readValue(barjson, AbstractBase.class);
System.out.println(barDeserialised);
}
}
class Foo extends AbstractBase {
public Data data;
@Override
public String toString() {
return "Foo[" + super.toString() + "; data=" + data + ']';
}
}
class Bar extends AbstractBase {
public String data;
public String toString() {
return "Bar[" + super.toString() + "; data=" + data + ']';
}
}
class Data {
public CustomObject object;
@Override
public String toString() {
return "Data[object=" + object + ']';
}
}
class CustomObject {
public long id;
public String fizz;
@Override
public String toString() {
return "CustomObject[id=" + id + "; fizz=" + fizz + ']';
}
}
class MetaData {
public String data;
@Override
public String toString() {
return "MetaData[data=" + data + ']';
}
}
class Owner {
public String name;
@Override
public String toString() {
return "Owner[name=" + name + ']';
}
}https://stackoverflow.com/questions/44122782
复制相似问题