我有一堂课,看起来像下面这样
public class MyClass { private String val1; private String val2; private Map<String,Object> context; // Appropriate accessors removed for brevity. ... }
我希望能够与Jackson进行往返,从对象到JSON再返回。我可以很好地序列化对象并接收以下输出:
{ "val1": "foo", "val2": "bar", "context": { "key1": "enumValue1", "key2": "stringValue1", "key3": 3.0 } }
我遇到的问题是,由于序列化映射中的值没有任何类型信息,因此无法正确地反序列化它们。例如,在上面的示例中,应将enumValue1反序列化为枚举值,而应反序列化为字符串。我已经看到了基于各种事物的类型的示例,但是在我的场景中,我不知道类型是什么(它们将是我事先不知道的用户生成的对象),所以我需要能够使用键值对序列化类型信息。我如何与杰克逊做到这一点?
作为记录,我使用的是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); }
由于这是一个基于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(); } }
我认为实现所需目标的最简单方法是使用:
ObjectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
这将在序列化的json中添加类型信息。
这是一个正在运行的示例,您需要适应于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); } }
该对象将被序列化为类似于以下内容的对象:
[ "so_27871226.MyClass", { "val1" : "foo", "val2" : "var", "context" : [ "java.util.HashMap", { "key3" : 3.0, "key2" : [ "so_27871226.Main$MyEnum", "enumValue1" ], "key1" : "stringValue1" } ] } ]
并且将正确反序列化,并且断言将通过。
顺便说一下,还有更多的方法可以做到这一点,请查看https://github.com/FasterXML/jackson- docs/wiki/JacksonPolymorphicDeserialization了解更多信息。
希望对您有所帮助。