Re-reading skipped children in custom deserializer

41 views
Skip to first unread message

Burak Emre Kabakcı

unread,
Feb 12, 2015, 7:47:08 AM2/12/15
to jackso...@googlegroups.com
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.

Tatu Saloranta

unread,
Feb 12, 2015, 12:08:40 PM2/12/15
to jackso...@googlegroups.com
Parser stream is not rewindable, so there is no way to re-parse things.

The usual way for buffering is to let parser handle its job and use `TokenBuffer` to hold contents (it implement `JsonGenerator` so copying is simple and efficient), then create `JsonParser` out of  `TokenBuffer`. This is more efficient than re-parsing, although obviously there is some overhead associated.
Another common alternative is to just parse into `JsonNode`: this is more convenient as it allows random-access within tree, but has bit more overhead (both memory and cpu time); although once again probably less than reparsing.

Challenge here, however, is that of holding onto contents. Serializers and deserializers are stateless, so they can not store this content.
The simplest way is probably to use Attributes of DeserializationContext: there are setAttribute() and getAttribute() methods. Since these are automatically cleared up after processing, it is a safe way for temporarily storing state and content.

Handling of co-constraints between properties is tricky, and there isn't much to help handling these. I think the most common method is actually to use constructors with @JsonCreator, and handle things there. I have had plans to add "multi-setter" support (for couple of years now) which would allow doing this in more granular way; but that does not yet exist, nor is there any code to support it. But this idea is why @JsonSetter is not deprecated; it would be used to indicate such multi-getter methods (multiple properties, or perhaps injectables).

I hope this helps,

-+ Tatu +-


--
You received this message because you are subscribed to the Google Groups "jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
To post to this group, send email to jackso...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages