Defining parameters for custom deserialization

2,007 views
Skip to first unread message

Tim Dudgeon

unread,
Jun 1, 2015, 5:05:21 AM6/1/15
to jackso...@googlegroups.com
I need to define custom parameters for deserialization - that is to specify some parameters that control how an individual deserialization happens.
I've worked out how to write a custom deserializer (extending StdDeserializer) and how to set that to a Module and register it to an ObjectMapper.
What I'm not clear about is the best way to specify these runtime parameters. The deserialize() method of JsonDeserializer takes a DeserializationContext parameter which might be what I need to pass in the parameters, but its not really clear to me how to use this.

Or to phrase the question a different way, I have a json object that I need to convert to a Java Map, with the Java types of the values being held externally to the json. e.g.
{"key1": "value1", "key2": "value2"}
When I deserialize I need to be able to say that key1 should be Banana.class and key2 should be Orange.class, but then next time I need to deseralize the keys and types will be different.
Its that mapping between key name and java type that I need to specify at runtime.

Thanks
Tim

Tatu Saloranta

unread,
Jun 1, 2015, 1:23:08 PM6/1/15
to jackso...@googlegroups.com
Good detective work so far, you are on the right track!

Concept of "Attributes" was added in Jackson 2.5, and you can add them via ObjectWriter / ObjectReader, on per-call basis. They are then accessible via DeserializationContext (and for serialization, SerializerProvider). ObjectReader/ObjectWriter define base values, and deserializers/serializers can both access (get) and modify (set) attribute values; any changes only affect current deserialization/serialization so they are fully thread-safe.
ObjectMapper can be thought of as a factory for thread-safe ObjectReaders and ObjectWriters, so quite a bit of functionality is only available via readers/writers, not mapper itself.

This mechanism was intended for both passing contextual values from the outside, and for primitive communication/state mechanism for (de)serializers that need some level of coordination, like parent (de)serializer passing values to a child, or vice versa.

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.

Tim Dudgeon

unread,
Jun 2, 2015, 9:05:31 AM6/2/15
to jackso...@googlegroups.com
Great thanks. That sounds on the lines of what I need.
But its not clear exactly how to got about this - where to set the Attributes so that they can are visible to the deserializer.
So, given code like this:

        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(MyClass.class, new MyClassDeserializer());
        mapper.registerModule(module);
        JsonParser parser = mapper.getFactory().createParser(someJson);
        MyClass my = parser.readValueAs(MyClass.class); 

How do I specify attributes so that they are visible to the deserializer in a thread safe manner,
I'm presumably not wanting to create a new ObjectMapper every time as that's a relatively expensive operation, so it needs to happen after module registration?

Thanks
Tim

Tatu Saloranta

unread,
Jun 2, 2015, 4:58:31 PM6/2/15
to jackso...@googlegroups.com
As I said earlier: you need to use ObjectReader, NOT ObjectMapper, for passing per-call attributes.

-+ Tatu +-


--

Tim Dudgeon

unread,
Jun 3, 2015, 11:11:43 AM6/3/15
to jackso...@googlegroups.com
OK, thanks. Got something working. For reference this is what it looks like:

        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(MyClass.class, new MyClassDeserializer());
        mapper.registerModule(module);
        
        ContextAttributes attrs = ContextAttributes.getEmpty().withSharedAttribute("mappings", mappings);
        ObjectReader reader = mapper.reader(MyClass.class).with(attrs);
        MyClass my = reader.readValue(jsonObject);

Tim

On Monday, 1 June 2015 10:05:21 UTC+1, Tim Dudgeon wrote:

Tatu Saloranta

unread,
Jun 3, 2015, 3:14:18 PM6/3/15
to jackso...@googlegroups.com
Ok good! And thank you for sharing the code,

-+ Tatu +-

--
Reply all
Reply to author
Forward
0 new messages