【问题标题】:How can I get Jackson to deserialize into my own Array implementation如何让 Jackson 反序列化为我自己的 Array 实现
【发布时间】:2016-06-17 03:54:46
【问题描述】:

鉴于我自己的数组实现MyArray<T>,我怎样才能让 Jackson 知道它,以便它能够从 JSON 数组反序列化为 MyArray<T>?到目前为止,我只得到了这个例外:

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

【问题讨论】:

  • 需要更多代码,发布MyArray类。
  • 也可能发生反序列化
  • 可能@Dariusz 怀疑我做同样的事情。问题是您的类没有扩展数组,而是有一个数组作为实例变量,这是数组操作发生的地方。您的 JSON 必须反映 MyArray 的结构(内部带有数组的对象可能会起作用)。这是我认为的问题,我不知道是否有某种方法可以告诉杰克逊将您的课程视为只是一个数组(但我希望有人能给您答案)
  • 您可以为 Jackson 编写自定义反序列化程序。虽然我从未尝试过使用自定义数组,但它也应该可以工作。

标签: java json jackson json-deserialization


【解决方案1】:

来自 libgdx 的 Array 类有一个接受数组的构造函数:public Array (T[] array)

不要尝试序列化 libgdx 数组,而是使用以数组为基础的简单类进行序列化/反序列化,然后根据反序列化数据创建 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!
}

【讨论】:

  • 这就是我现在正在做的事情,但是我认为直接使用 LibGDX 数组而不是来回转换会更优雅。
  • 您必须修改 libgdx 数组的代码,我猜 - 仅使用适当的注释标记用于序列化的自定义方法。或者使用 XmlAdapter,我认为它适用于 json,但我不确定。
【解决方案2】:

一种方法是编写类似的序列化程序

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)注释保存这样一个数组的属性。
如果你直接使用你的数组实现,而不是在容器类中,这个页面有一个如何在运行时注册序列化处理程序的示例http://wiki.fasterxml.com/JacksonHowToCustomSerializers

我应该注意,在这个答案中,我使用的是 Jackson 1.9 API,而 2.x 可能略有不同。根据http://wiki.fasterxml.com/JacksonUpgradeFrom19To20,最明显的区别是包名的变化和一些类的位置。否则这段代码应该不受影响。

【讨论】:

    【解决方案3】:

    正如 Dariusz 所提到的,最好利用 Array 类的构造函数接受普通数组这一事实。

    看,如果您使用默认序列化程序 - 您的序列化为 JSON 的数组将如下所示:

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

    这显然是在浪费空间,除非您希望保留 sizeordered 字段。

    我建议您更改序列化对象的方式,使其看起来更像普通数组,另一方面 - 反序列化可以再次构建 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);
    

    您将在这些类型之间进行透明转换

    【讨论】:

    • 谢谢!我最喜欢这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 2019-06-12
    • 2019-04-10
    • 1970-01-01
    相关资源
    最近更新 更多