I have a deserializer for a specific class which needs some ordering while reading fields.
Let's say I have two fields in my class (field1
and field2
) and in order to read field2
, it first needs field1
.
For example for the following json data it works because when the deserializer parses field2
, field1
is already set:
{"field1": 3, "field2": 4}
However if we reverse the fields:
{"field2": 4, "field1": 3}
I need to skip field2
via jp.skipChildren
because field1
is not set. When field1
is parsed, Jackson should re-read and parse field2
.
One option is to parse field2 instead of skipping and hold it in a variable so that when field1 is set, it can use the variable that holds data in field2. However; based on the value of field1
, I may not need to parse field2
so I'm looking for a better solution since performance is critical in this part of the code.
I'm using Mapper.readValue(byte[], MyClass.class)
method and it seems Jackson uses ReaderBasedJsonParser
for parsing. Even though it's possible to get token position, I couldn't find a way to set token position.
Finally I found a way to do it. It's actually a workaround but it passes the tests that I wrote.
When you pass byte array to mapper.readValue it uses ReaderBasedJsonParser
which iterates through the array and parse the JSON tree.
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);
}
}
When you use this JsonParser
, the JsonParser
instance that will be passed to your deserializer EventDeserializer.deserialize(JsonParser, DeserializationContext) will be a SaveableReaderBasedJsonParser
so you can safely cast it.
When you want to save the position, call jp.save()
so that when you need to go back, you can call just call jp.load()
.
As I said, it's actually a workaround but when you need this kind of feature and don't want to parse the tree twice for performance reasons, you may give it a try.