【问题标题】:Jackson Stateful Deserialization杰克逊状态反序列化
【发布时间】:2015-07-26 09:44:36
【问题描述】:

我有如下 JSON:

{
    systemId: 7
    name: "Phil"
    data: "XYZ"

    pointers: [
        {
            systemId: 23
            name: "Peter"
        },
        {
            systemId: 27
            name: "Jeroen"
        }
    ]
}

在上述 JSON 的 POJO 等效项中,所有字段都是最终字段。现在,在反序列化期间,我希望能够在杰克逊设置 POJO 之前修改 systemId 字段。此外,更改后的 systemId 实际上将由有状态对象提供,作为 JSON 中当前 systemId 的函数。例如,要在反序列化 POJO 上设置的新 systemId 可能由如下类的实例提供:

public class SystemIdProvider {
    ...
    public long getNewSystemId(long oldSystemId) {
        // do something with the oldSystemId and
        // the current state of this object to get the newSystemId
        return newSystemId;
    }
}

有没有一种方法可以在 Jackson 反序列化 JSON 时向 Jackson 提供上述类的实例,并让 Jackson 在将其设置到它创建的 POJO 之前使用此对象获取 newSystemId?

请注意,上面的 JSON 只是实际 JSON 的一个小 sn-p,因此可能包含数百个上述对象。而且我想为每个反序列化提供 SystemIdProvider 类的新实例,因为它维护的“状态”也基于它迄今为止遇到的 systemIds。因此,每次反序列化都需要从一个干净的状态开始。

感谢任何意见。

【问题讨论】:

  • 我认为您需要探索此处提到的一些选项以解决相关但不相同的问题 - stackoverflow.com/questions/7105745/…
  • 感谢魔杖制造者。我已经知道这些配置选项了。

标签: java json jackson


【解决方案1】:

您需要为此编写一个自定义反序列化程序。假设您有以下 POJO:

public class MyPojo {

    private final long systemId;
    private final String foo;

    public MyPojo(long systemId, String foo) {
        this.systemId = systemId;
        this.foo = foo;
    }

    // getters and other methods
}

systemId 字段编写自定义反序列化器:

public class SystemIdDeserializer extends StdDeserializer<Long> {

    public SystemIdDeserializer() {
        super(Long.class);
    }

    @Override
    public Long deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        SystemIdProvider systemIdProvider = (SystemIdProvider) ctxt.getAttribute("systemIdProvider");
        Long oldSystemId = _parseLong(jp, ctxt);
        return systemIdProvider.getNewSystemId(oldSystemId);
    }
}

使用systemId字段上的@JsonDeserialize注解来注册反序列化器:

@JsonDeserialize(using = SystemIdDeserializer.class)
private final long systemId;

要使SystemIdProviderDeserializationContext 中可用,请像这样调用Jackson 的映射器:

ObjectMapper mapper = new ObjectMapper();
MyPojo deserialized = mapper.reader(MyPojo.class)
        .withAttribute("systemIdProvider", new SystemIdProvider())
        .readValue(json);

【讨论】:

  • 非常感谢您的回答和代码示例。每次反序列化 JSON 时,我都需要一个新的 SystemIdProvider 实例,因为它使用迄今为止在 JSON 中遇到的 systemIds 构建其状态。它不是单例。出现了我的问题。我想知道是否可以以某种方式将其“注入”到 DeserializationContext 中。
  • 另一件事是,我想对一个字段使用自定义反序列化,即 systemId 而不是整个类。
  • 非常感谢 hzpz!这看起来正是我正在寻找的东西。我在上下文中查看injectableValues,从未见过属性的东西。很快就会尝试一下。
猜你喜欢
  • 1970-01-01
  • 2015-05-13
  • 2015-04-07
  • 1970-01-01
  • 2017-12-19
  • 1970-01-01
  • 1970-01-01
  • 2012-11-19
  • 2016-10-23
相关资源
最近更新 更多