【问题标题】:Custom deserialization of List using Jackson使用 Jackson 对 List 进行自定义反序列化
【发布时间】:2016-03-14 14:18:24
【问题描述】:

我正在尝试编写一个自定义反序列化程序,以减少我从其他地方收到的大量数据。我从反序列化器返回一个自定义对象列表。

我的问题是,如果这是我的自定义反序列化器,我该怎么做:

public class MyCustomDeserializer extends JsonDeserializer<List<CustomClass>> { ... }

我当然不能这样做:

final SimpleModule module = new SimpleModule();
module.addDeserializer(List<CustomClass>.class, new MyCustomDeserializer());

这样的事情会起作用吗?

final List<CustomClass> response = Arrays.asList(objectMapper.readValue(stringBean, CustomClass[].class));

如果这确实有效,我觉得它有点令人困惑和“危险”?反序列化不是在 asList 方法调用内部完成的吗?所以它基本上将 List 映射到 array[] ?

我了解了 TypeReference,所以我可以像这样使用它:

objectMapper.readValue(stringBean, new TypeReference<List<CustomClass>>(){});

但我听说它比较慢。

我也不想为列表创建一个容器,并在反序列化中返回它,因为这意味着它将被包装在另一个 json 对象中,我只是希望我的端点产生类似的东西:

[{object1}, {object2}]

// instead of

{"Output" : [{object1}, {object2}]}

编辑:

似乎我误解了杰克逊在这两种情况下如何使用我的解串器:

final List<CustomClass> response = Arrays.asList(objectMapper.readValue(stringBean, CustomClass[].class));
// or
objectMapper.readValue(stringBean, new TypeReference<List<CustomClass>>(){});

看起来反序列化器被调用了两次,对数组中的每个对象调用一次。我认为整个数组将被视为一个整体。为了消除混乱,我的意思是:

我收到并尝试反序列化的 json 看起来像这样:

[
  {
    "Data" : {
      "id" : "someId",
      "otherThing" : "someOtherThing"
    },
    "Message" : "OK"
  },
  {
    "Data" : null,
    "Message" : "Object not found for id blabla"
  }
]

所以我虽然这是我的反序列化器中的内容,但正如我之前所说,我似乎实际上从该数组中获取了每个“条目”并多次调用它。

【问题讨论】:

  • 还需要说明我使用@JsonDeserializer 注释在bean 上注册了反序列化器。
  • 使用ObjectMapperTypeFactory;它允许您根据需要创建类型描述,即“自定义类列表”。另外,请提及您使用的 Jackson 版本。
  • 我使用的是 jackson 2.4 版本。你能提供一些使用类型工厂方法的材料吗?谢谢。

标签: java json jackson deserialization


【解决方案1】:

这两行就够了。

ArrayNode arrayNode = (ArrayNode) objectMapper.readTree(stringBean);
List<CustomClass> response = objectMapper.convertValue(arrayNode, List.class); 

稍后谢谢!

【讨论】:

    【解决方案2】:

    我通过将自定义反序列化器添加到模型类中的属性并使用 JsonDeserialize 注释的 contentUsing() 方法来解决这个问题,如下所示:

    @JsonDeserialize(contentUsing = MyCustomDeserializer.class)
    private List<CustomClass> customClassObjList;
    

    其中 MyCustomDeserializer 类是自定义 Jackson JSON 反序列化器,定义为:

    public class MyCustomDeserializer extends JsonDeserializer<CustomClass> {
        
        @Override
        public CustomClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            ...
        }
    }
    

    【讨论】:

    • 这是否意味着 Jackson 可以自动反序列化 List 即使您只为单个 CustomClass 对象定义了反序列化?
    • 是的。诀窍是使用contentUsing 而不是using
    【解决方案3】:

    首先,如果您在 bean CustomClass 上使用注释注册了自定义反序列化器,那么反序列化器应该处理 CustomClass 的一个实例,而不是一个集合,因此应该定义:

    public class MyCustomDeserializer extends JsonDeserializer<CustomClass> {
            @Override
            public CustomClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException
            {
                ...
            }
    }
    

    现在您可以使用 Jackson 的类型工厂向映射器传递所需的类型信息

    JavaType customClassCollection = objectMapper.getTypeFactory().constructCollectionType(List.class, CustomClass.class);
    List<CustomClass> beanList = (List<CustomClass>)objectMapper.readValue(stringBean, customClassCollection);
    

    【讨论】:

    • 我想通了,然后我看到了你的答案。我会接受这是正确的答案,因为这实际上是我想要做的。
    • 自定义反序列化器的优秀示例,以及如何操作它以反序列化 JSON 对象列表。
    猜你喜欢
    • 2021-05-29
    • 1970-01-01
    • 2020-12-08
    • 2014-08-02
    • 2013-10-10
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    相关资源
    最近更新 更多