Reading skipped children in Jackson Custom Deserializer

42 views
Skip to first unread message

Burak Emre Kabakcı

unread,
Jun 12, 2016, 7:22:21 PM6/12/16
to jackson-user
We have JSON data similar to this one:
{
"schema":"table1",
"data":[
{
"field1":"12:00:00",
"field2":"2016-06-12T23:10:07.135Z",
"field3":100}]}



Schema attribute represents the actual types of the JSON fields, for example field1 is time, field2 is timestamp and field3 is tinyint. I created a custom deserializer, it needs the schema name in order to parse the "data" field since it must know the actual types. The problem is that is the "schema" property comes after "data" property, the deserializer doesn't know how to parse the fields since it doesn't know the schema yet.

The solution that I found is to save the cursor position, skip the children and read the "schema" attribute and then set the cursor position again. (http://stackoverflow.com/a/28531031/689144) However this is quite hacky and is not reliable so I'm looking for an alternative. Unfortunately the performance is critical when parsing JSON data so reading the "data" field as Map and casting the attributes to actual type is expensive for us. Also Jackson deserializer is quite powerful and provide ways to read the values as primitive types efficiently and reliably so I would rather stick with that.

Tatu Saloranta

unread,
Jun 12, 2016, 11:02:17 PM6/12/16
to jackso...@googlegroups.com
Not sure if it helps, but internally Jackson uses `TokenBuffer` for uses like this: unprocessed content is appended into buffer, and once everything is gathered, content is re-read using `JsonParser` instance created from `TokenBuffer`. This is quite efficient given that no decoding step is needed, and convenient as `TokenBuffer` implements `JsonGenerator` directly (so copying using `generator.copyToken()`/`copyStructure()` can be used) and allows uses custon buffer-backed `JsonParser` implementation.

So one possibility could be to use converting deserializer, specifying `TokenBuffer` as type Jackson should bind data as, then read everything from that.

Alternatively you could make custom deserializer use TokenBuffer if and only if needed -- Jackson itself does this for polymorphic type handling, and buffering is only needed if the type id is NOT the first property found.

-+ 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.

Burak Emre

unread,
Jun 13, 2016, 7:41:30 AM6/13/16
to jackso...@googlegroups.com
Wow, that was much more easy than I expected. Now, when the parser doesn't know the schema when processing "data" field, I simply read  value as TokenBuffer as suggested (buffer = jp.readValueAs(TokenBuffer.class)) and when the processing is done and I don't have the data yet, I check the buffer and read it again with buffer.asParser(jp). Thanks Tatu!

--
You received this message because you are subscribed to a topic in the Google Groups "jackson-user" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jackson-user/MM2E2JOVhJM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jackson-user...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages