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:
我希望能够与杰克逊从JSON到JSON再往返。我可以将对象序列化为精细并接收以下输出:
{
"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?
我遇到的问题是,由于序列化映射中的值没有任何类型信息,因此它们不会正确反序列化。例如,在上面的示例中,enumValue1应该反序列化为枚举值,而是反序列化为String。我已经看到了基于各种类型的类型的示例,但在我的场景中,我不知道类型是什么(它们将是用户生成的对象,我不会事先知道)所以我需要成为能够使用键值对序列化类型信息。我怎样才能与杰克逊达成这个目标?
For the record, I'm using Jackson version 2.4.2. The code I'm using to test the round trip is as follows:
为了记录,我使用Jackson版本2.4.2。我用来测试往返的代码如下:
@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:
由于这是一个基于Spring的项目,因此映射器的创建方式如下:
@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();
}
}
1 个解决方案
#1
16
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.
这将在序列化的json中添加类型信息。
Here you are a running example, that you will need to adapt to Spring:
在这里你是一个运行的例子,你将需要适应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 https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization for more info.
顺便提一下,有更多的方法,请查看https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization了解更多信息。
I hope it will help.
我希望它会有所帮助。
#1
16
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.
这将在序列化的json中添加类型信息。
Here you are a running example, that you will need to adapt to Spring:
在这里你是一个运行的例子,你将需要适应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 https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization for more info.
顺便提一下,有更多的方法,请查看https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization了解更多信息。
I hope it will help.
我希望它会有所帮助。