我怎样才能让杰克逊反序列化到我自己的数组实现中
How can I get Jackson to deserialize into my own Array implementation
鉴于我自己的数组实现 MyArray<T>
,我如何让 Jackson 知道它,以便它能够从 JSON 数组反序列化为 MyArray<T>
?到目前为止,我只得到这个例外:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of MyArray out of START_ARRAY token
来自 libgdx 的数组 class 有一个接受数组的构造函数:public Array (T[] array)
.
不要尝试序列化 libgdx 数组,而是使用一个简单的 class 数组作为 serialization/desrialization 的基础,然后基于 libgdx 创建一个数组反序列化数据。
一般来说,只序列化 POJO 类型的对象是一个很好的规则。
简而言之:
{
//serialize:
com.badlogic.gdx.utils.Array<MyObj> arr = ...;
MyObj[] myArr = arr.toArray();
MyCustomContainer cont = new MyCustomContainer(myArr);
String serializedData = mapper.writeValueAsString(cont);
// do sth with the data
}
{
//deserialize
MyCusomContainer cont = mapper.readValue(..., MyCustomContainer.class);
com.badlogic.gdx.utils.Array<MyObj> arr = new com.badlogic.gdx.utils.Array<MyObj>(cont.getArray());
// done!
}
一种方法是编写一个像
这样的序列化器
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.ser.std.SerializerBase;
public class MyArraySerializer extends SerializerBase<MyArray> {
protected MyArraySerializer() {
super(MyArray.class);
}
@Override
public void serialize(MyArray myArray, JsonGenerator gen, SerializerProvider p)
throws IOException, JsonGenerationException {
gen.writeStartArray();
Iterator<MyObject> it = myArray.iterator();
while (it.hasNext()) {
MyObject ob = it.next();
gen.writeObject(p);
if (it.hasNext()) {
gen.writeRaw(',');
}
}
gen.writeEndArray();
}
}
还有像
这样的反序列化器
import java.io.IOException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
public class MyArrayDeserializer extends JsonDeserializer<MyArray> {
@Override
public MyArray deserialize(JsonParser parser, DeserializationContext ctx)
throws IOException, JsonProcessingException {
MyObject[] obs = parser.readValueAs(MyObject[].class);
return new MyArray(obs); //presuming you have a copy-constructor
}
}
然后用@JsonSerialize(using = MyArraySerializer.class) @JsonDeserialize(using = MyArrayDeserializer.class)
注释保存这样一个数组的属性。
如果您直接使用数组实现,而不是在容器内 class,此页面有一个示例,说明如何在 运行 时间 http://wiki.fasterxml.com/JacksonHowToCustomSerializers
注册序列化处理程序
我应该注意,在这个答案中我使用的是 Jackson 1.9 API,2.x 可能略有不同。根据 http://wiki.fasterxml.com/JacksonUpgradeFrom19To20 ,最显着的差异是包名称的变化以及一些 classes 所在的位置。否则这段代码应该不受影响。
正如 Dariusz 所提到的,利用 Array
class 具有接受普通数组的构造函数这一事实是很好的。
看,如果您使用默认序列化器 - 您的数组序列化为 JSON 将如下所示:
{"items":["item1","item2"],"size":2,"ordered":true}
这显然是对 space 的浪费,除非您希望保留 size
和 ordered
字段。
我建议您更改序列化对象的方式,使其看起来更像普通数组,另一方面 - 反序列化可以再次构建 Array
对象。
如果添加以下一对序列化器和反序列化器:
SimpleModule module = new SimpleModule();
module.addDeserializer(Array.class, new StdDelegatingDeserializer<>(
new StdConverter<Object[], Array>() {
@Override
public Array convert(Object[] value) {
return new Array(value);
}
}));
module.addSerializer(Array.class, new StdDelegatingSerializer(
new StdConverter<Array, Object>() {
@Override
public Object convert(Array value) {
return value.toArray();
}
}));
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
您将在这些类型之间进行透明转换
鉴于我自己的数组实现 MyArray<T>
,我如何让 Jackson 知道它,以便它能够从 JSON 数组反序列化为 MyArray<T>
?到目前为止,我只得到这个例外:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of MyArray out of START_ARRAY token
来自 libgdx 的数组 class 有一个接受数组的构造函数:public Array (T[] array)
.
不要尝试序列化 libgdx 数组,而是使用一个简单的 class 数组作为 serialization/desrialization 的基础,然后基于 libgdx 创建一个数组反序列化数据。
一般来说,只序列化 POJO 类型的对象是一个很好的规则。
简而言之:
{
//serialize:
com.badlogic.gdx.utils.Array<MyObj> arr = ...;
MyObj[] myArr = arr.toArray();
MyCustomContainer cont = new MyCustomContainer(myArr);
String serializedData = mapper.writeValueAsString(cont);
// do sth with the data
}
{
//deserialize
MyCusomContainer cont = mapper.readValue(..., MyCustomContainer.class);
com.badlogic.gdx.utils.Array<MyObj> arr = new com.badlogic.gdx.utils.Array<MyObj>(cont.getArray());
// done!
}
一种方法是编写一个像
这样的序列化器import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.ser.std.SerializerBase;
public class MyArraySerializer extends SerializerBase<MyArray> {
protected MyArraySerializer() {
super(MyArray.class);
}
@Override
public void serialize(MyArray myArray, JsonGenerator gen, SerializerProvider p)
throws IOException, JsonGenerationException {
gen.writeStartArray();
Iterator<MyObject> it = myArray.iterator();
while (it.hasNext()) {
MyObject ob = it.next();
gen.writeObject(p);
if (it.hasNext()) {
gen.writeRaw(',');
}
}
gen.writeEndArray();
}
}
还有像
这样的反序列化器import java.io.IOException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
public class MyArrayDeserializer extends JsonDeserializer<MyArray> {
@Override
public MyArray deserialize(JsonParser parser, DeserializationContext ctx)
throws IOException, JsonProcessingException {
MyObject[] obs = parser.readValueAs(MyObject[].class);
return new MyArray(obs); //presuming you have a copy-constructor
}
}
然后用@JsonSerialize(using = MyArraySerializer.class) @JsonDeserialize(using = MyArrayDeserializer.class)
注释保存这样一个数组的属性。
如果您直接使用数组实现,而不是在容器内 class,此页面有一个示例,说明如何在 运行 时间 http://wiki.fasterxml.com/JacksonHowToCustomSerializers
我应该注意,在这个答案中我使用的是 Jackson 1.9 API,2.x 可能略有不同。根据 http://wiki.fasterxml.com/JacksonUpgradeFrom19To20 ,最显着的差异是包名称的变化以及一些 classes 所在的位置。否则这段代码应该不受影响。
正如 Dariusz 所提到的,利用 Array
class 具有接受普通数组的构造函数这一事实是很好的。
看,如果您使用默认序列化器 - 您的数组序列化为 JSON 将如下所示:
{"items":["item1","item2"],"size":2,"ordered":true}
这显然是对 space 的浪费,除非您希望保留 size
和 ordered
字段。
我建议您更改序列化对象的方式,使其看起来更像普通数组,另一方面 - 反序列化可以再次构建 Array
对象。
如果添加以下一对序列化器和反序列化器:
SimpleModule module = new SimpleModule();
module.addDeserializer(Array.class, new StdDelegatingDeserializer<>(
new StdConverter<Object[], Array>() {
@Override
public Array convert(Object[] value) {
return new Array(value);
}
}));
module.addSerializer(Array.class, new StdDelegatingSerializer(
new StdConverter<Array, Object>() {
@Override
public Object convert(Array value) {
return value.toArray();
}
}));
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
您将在这些类型之间进行透明转换