杰克逊状态反序列化

Jackson Stateful Deserialization

我有一个 JSON 如下所示:

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

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

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

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

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

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

欢迎任何意见。

您需要为此编写自定义反序列化程序。假设您有以下 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);