Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 792 Vote(s) - 3.49 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Jackson: Deserialize to a Map<String, Object> with correct type for each value

#1
I have a class that looks like the following

public class MyClass {
private String val1;
private String val2;
private Map<String,Object> context;
// Appropriate accessors removed for brevity.
...
}

I'm looking to be able to make the round trip with Jackson from object to JSON and back. I can serialize the object above fine and receive the following output:

{
"val1": "foo",
"val2": "bar",
"context": {
"key1": "enumValue1",
"key2": "stringValue1",
"key3": 3.0
}
}

The issue I'm running into is that since the values in the serialized map do not have any type information, they are not deserialized correctly. For example, in the sample above, enumValue1 should be deserialized as an enum value but is instead deserialized as a String. I've seen examples for basing what type on a variety of things, but in my scenario, I won't know what the types are (they will be user generated objects that I won't know in advance) so I need to be able to serialize the type information with the key value pair. How can I accomplish this with Jackson?

For the record, I'm using Jackson version 2.4.2. The code I'm using to test the round trip is as follows:

@Test
@SuppressWarnings("unchecked")
public void testJsonSerialization() throws Exception {
// Get test object to serialize
T serializationValue = getSerializationValue();
// Serialize test object
String json = mapper.writeValueAsString(serializationValue);
// Test that object was serialized as expected
assertJson(json);
// Deserialize to complete round trip
T roundTrip = (T) mapper.readValue(json, serializationValue.getClass());
// Validate that the deserialized object matches the original one
assertObject(roundTrip);
}

Since this is a Spring based project, the mapper is being created as follows:

@Configuration
public static class SerializationConfiguration {

@Bean
public ObjectMapper mapper() {
Map<Class<?>, Class<?>> mixins = new HashMap<Class<?>, Class<?>>();
// Add unrelated MixIns
..

return new Jackson2ObjectMapperBuilder()
.featuresToDisable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)
.dateFormat(new ISO8601DateFormatWithMilliSeconds())
.mixIns(mixins)
.build();
}
}




Reply

#2
I think the simplest way of achieve what you want is using:

ObjectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

This will add type information in the serialized json.

Here you are a running example, that you will need to adapt to Spring:

public class Main {

public enum MyEnum {
enumValue1
}

public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();

MyClass obj = new MyClass();
obj.setContext(new HashMap<String, Object>());

obj.setVal1("foo");
obj.setVal2("var");
obj.getContext().put("key1", "stringValue1");
obj.getContext().put("key2", MyEnum.enumValue1);
obj.getContext().put("key3", 3.0);

mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);

System.out.println(json);

MyClass readValue = mapper.readValue(json, MyClass.class);
//Check the enum value was correctly deserialized
Assert.assertEquals(readValue.getContext().get("key2"), MyEnum.enumValue1);
}

}

The object will be serialized into something similar to:

[ "so_27871226.MyClass", {
"val1" : "foo",
"val2" : "var",
"context" : [ "java.util.HashMap", {
"key3" : 3.0,
"key2" : [ "so_27871226.Main$MyEnum", "enumValue1" ],
"key1" : "stringValue1"
} ]
} ]

And will be deserialized back correctly, and the assertion will pass.

Bytheway there are more ways of doing this, please look at

[To see links please register here]

for more info.

I hope it will help.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through