杰克逊有状态反序列化

时间:2015-07-26 09:44:37

标签: java json jackson

我有一个类似以下的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可能由类的实例提供,如下所示:

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时为杰克逊提供上述类的实例,并让杰克逊在将它设置为创建的POJO之前使用此对象获取newSystemId?

请注意,上面的JSON只是实际JSON的一小部分,因此可能包含上面数百个这样的对象。我想为每个反序列化提供一个SystemIdProvider类的新实例,因为它维护的“状态”也是基于它到目前为止遇到的systemIds。因此,每次反序列化都需要以干净状态开始。

赞赏任何意见。

1 个答案:

答案 0 :(得分: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);
    }
}

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

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

要使SystemIdProvider中的DeserializationContext可用,请按照以下方式致电杰克逊的映射器:

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