Jackson Custom Deserializer 中跳过了读取 children
Reading skipped children in Jackson Custom Deserializer
我有一个用于特定 class 的反序列化器,它在读取字段时需要一些排序。
假设我的 class 中有两个字段(field1
和 field2
),为了读取 field2
,它首先需要 field1
.
例如,对于以下 json 数据,它可以工作,因为当反序列化器解析 field2
时,field1
已经设置:
{"field1": 3, "field2": 4}
然而,如果我们反转字段:
{"field2": 4, "field1": 3}
我需要通过 jp.skipChildren
跳过 field2
,因为 field1
没有设置。解析field1
时,Jackson应该re-read,解析field2
.
一个选项是解析field2而不是跳过并将其保存在一个变量中,这样当设置field1时,它可以使用保存field2中数据的变量。然而;基于 field1
的值,我可能不需要解析 field2
所以我正在寻找更好的解决方案,因为这部分代码的性能至关重要。
我正在使用 Mapper.readValue(byte[], MyClass.class)
方法,Jackson 似乎使用 ReaderBasedJsonParser
进行解析。虽然可以获取令牌位置,但我找不到设置令牌位置的方法。
自定义解串器需要使用流 API。没有办法返回,reparse等
您是否为包含需要这种特殊处理的字段的字段类型或 class 注册了自定义反序列化程序?
如果您为包含这些字段的 class 注册反序列化器,您可以只使用流 API,读取实例的所有字段,临时存储它们,例如在 HashMap 中,然后分配值。
顺便说一句:您的问题闻起来像 XY 问题。也许你应该post另一个问题的原因,你需要在这里解决这个问题,看看是否有更好的方法。
终于找到办法了。这实际上是一种解决方法,但它通过了我编写的测试。
当您将字节数组传递给 mapper.readValue 时,它使用 ReaderBasedJsonParser
遍历数组并解析 JSON 树。
public static class SaveableReaderBasedJsonParser extends ReaderBasedJsonParser {
private int savedInputPtr = -1;
public SaveableReaderBasedJsonParser(IOContext ctxt, int features, Reader r, ObjectCodec codec, CharsToNameCanonicalizer st, char[] inputBuffer, int start, int end, boolean bufferRecyclable) {
super(ctxt, features, r, codec, st, inputBuffer, start, end, bufferRecyclable);
}
public void save() {
savedInputPtr = _inputPtr;
}
public boolean isSaved() {
return savedInputPtr>-1;
}
public void load() {
_currToken = JsonToken.START_OBJECT;
_inputPtr = savedInputPtr;
_parsingContext = _parsingContext.createChildObjectContext(0, 0);
}
}
当您使用此 JsonParser
时,将传递给反序列化器 EventDeserializer.deserialize(JsonParser, DeserializationContext) 的 JsonParser
实例将是一个 SaveableReaderBasedJsonParser
,因此您可以安全投射。
当你想保存位置时,调用jp.save()
,这样当你需要返回时,你可以直接调用jp.load()
。
正如我所说,这实际上是一种解决方法,但是当您需要这种功能并且不想出于性能原因对树进行两次解析时,您可以尝试一下。
我有一个用于特定 class 的反序列化器,它在读取字段时需要一些排序。
假设我的 class 中有两个字段(field1
和 field2
),为了读取 field2
,它首先需要 field1
.
例如,对于以下 json 数据,它可以工作,因为当反序列化器解析 field2
时,field1
已经设置:
{"field1": 3, "field2": 4}
然而,如果我们反转字段:
{"field2": 4, "field1": 3}
我需要通过 jp.skipChildren
跳过 field2
,因为 field1
没有设置。解析field1
时,Jackson应该re-read,解析field2
.
一个选项是解析field2而不是跳过并将其保存在一个变量中,这样当设置field1时,它可以使用保存field2中数据的变量。然而;基于 field1
的值,我可能不需要解析 field2
所以我正在寻找更好的解决方案,因为这部分代码的性能至关重要。
我正在使用 Mapper.readValue(byte[], MyClass.class)
方法,Jackson 似乎使用 ReaderBasedJsonParser
进行解析。虽然可以获取令牌位置,但我找不到设置令牌位置的方法。
自定义解串器需要使用流 API。没有办法返回,reparse等
您是否为包含需要这种特殊处理的字段的字段类型或 class 注册了自定义反序列化程序?
如果您为包含这些字段的 class 注册反序列化器,您可以只使用流 API,读取实例的所有字段,临时存储它们,例如在 HashMap 中,然后分配值。
顺便说一句:您的问题闻起来像 XY 问题。也许你应该post另一个问题的原因,你需要在这里解决这个问题,看看是否有更好的方法。
终于找到办法了。这实际上是一种解决方法,但它通过了我编写的测试。
当您将字节数组传递给 mapper.readValue 时,它使用 ReaderBasedJsonParser
遍历数组并解析 JSON 树。
public static class SaveableReaderBasedJsonParser extends ReaderBasedJsonParser {
private int savedInputPtr = -1;
public SaveableReaderBasedJsonParser(IOContext ctxt, int features, Reader r, ObjectCodec codec, CharsToNameCanonicalizer st, char[] inputBuffer, int start, int end, boolean bufferRecyclable) {
super(ctxt, features, r, codec, st, inputBuffer, start, end, bufferRecyclable);
}
public void save() {
savedInputPtr = _inputPtr;
}
public boolean isSaved() {
return savedInputPtr>-1;
}
public void load() {
_currToken = JsonToken.START_OBJECT;
_inputPtr = savedInputPtr;
_parsingContext = _parsingContext.createChildObjectContext(0, 0);
}
}
当您使用此 JsonParser
时,将传递给反序列化器 EventDeserializer.deserialize(JsonParser, DeserializationContext) 的 JsonParser
实例将是一个 SaveableReaderBasedJsonParser
,因此您可以安全投射。
当你想保存位置时,调用jp.save()
,这样当你需要返回时,你可以直接调用jp.load()
。
正如我所说,这实际上是一种解决方法,但是当您需要这种功能并且不想出于性能原因对树进行两次解析时,您可以尝试一下。