简体   繁体   English

我如何让Jackson反序列化到我自己的Array实现中

[英]How can I get Jackson to deserialize into my own Array implementation

Given my own array implementation MyArray<T> , how can I make it known to Jackson, so that it is able to deserialize from a JSON Array into MyArray<T> ? 给定我自己的数组实现MyArray<T> ,我如何让Jackson知道它,以便它能够从JSON数组反序列化为MyArray<T> So far I am only getting this exception: 到目前为止,我只收到此异常:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of MyArray out of START_ARRAY token

The Array class from libgdx has a constructor which accepts an array: public Array (T[] array) . libgdx中的Array类具有一个接受数组的构造函数: public Array (T[] array)

Instead of trying to serialize libgdx array use a simple class with an array as a base for serialization/desrialization, and then create a libgdx array based on the deserialized data. 与其尝试序列化libgdx数组,不如使用带有数组的简单类作为序列化/反序列化的基础,然后基于反序列化的数据创建libgdx数组。

In general it is a good rule to serialize only POJO-type objects. 通常,仅序列化POJO类型的对象是一个好规则。

In short: 简而言之:

{
     //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!
}

As Dariusz mentioned, it's good to take advantage of the fact that Array class has constructor accepting normal array. 正如Dariusz所提到的,利用Array类具有接受常规数组的构造函数这一事实是很好的。

Look, if you use default serializer - your array serialized to JSON would look like: 看,如果您使用默认的序列化程序,则序列化为JSON的数组如下所示:

{"items":["item1","item2"],"size":2,"ordered":true}

it's clearly a waste of space, unless you want size and ordered fields to be preserved. 除非您希望保留sizeordered字段,否则这显然是在浪费空间。

I suggest you changing the way you serialize your object so that it would look more like normal array, on the other end - deserialization can build Array object again. 我建议您更改序列化对象的方式,使其看上去更像普通数组,另一方面,反序列化可以再次构建Array对象。

If you add following pair of serializer and deserializer: 如果添加以下对串行器和解串器:

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);

you will have transparent conversion between these types 您将在这些类型之间进行透明转换

One way to do it is to write a serializer like 一种方法是编写一个类似

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();
    }
}

And a deserializer like 还有一个反序列化器

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
    }
}

Then annotate the property that holds such an array with @JsonSerialize(using = MyArraySerializer.class) @JsonDeserialize(using = MyArrayDeserializer.class) . 然后使用@JsonSerialize(using = MyArraySerializer.class) @JsonDeserialize(using = MyArrayDeserializer.class)注释保存此类数组的属性。
If you use your array implementation directly, instead of inside a container class, this page has an example of how to register serialization handlers at run-time http://wiki.fasterxml.com/JacksonHowToCustomSerializers 如果直接使用数组实现而不是在容器类内部使用,则此页面提供了一个示例,该示例如何在运行时注册序列化处理程序http://wiki.fasterxml.com/JacksonHowToCustomSerializers

I should note that in this answer I am using the Jackson 1.9 API and the 2.x may be slightly different. 我应该注意,在此答案中,我使用的是Jackson 1.9 API,而2.x可能略有不同。 According to http://wiki.fasterxml.com/JacksonUpgradeFrom19To20 the most noticeable differences are the changes in package names and where some classes are located. 根据http://wiki.fasterxml.com/JacksonUpgradeFrom19To20 ,最明显的区别是包名称的更改以及某些类的位置。 Otherwise this code should be unaffected. 否则,该代码将不受影响。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM