Serialize / Deserialize Map com Jackson

Eu tenho uma class que se parece com o seguinte

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

Eu estou olhando para poder fazer a viagem com Jackson de object para JSON e de volta. Eu posso serializar o object acima bem e receber a seguinte saída:

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

O problema que estou encontrando é que, como os valores no mapa serializado não possuem informações de tipo, eles não são desserializados corretamente. Por exemplo, no exemplo acima, enumValue1 deve ser desserializado como um valor de enum, mas é desserializado como uma String. Eu vi exemplos para basear o tipo em uma variedade de coisas, mas no meu cenário, eu não sei o que os tipos são (eles serão objects gerados pelo usuário que eu não saberei de antemão) então eu preciso ser capaz de serializar as informações de tipo com o par de valores-chave. Como posso conseguir isso com Jackson?

Para o registro, eu estou usando Jackson versão 2.4.2. O código que estou usando para testar a viagem de ida e volta é o seguinte:

 @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); } 

Como esse é um projeto baseado em Spring, o mapeador está sendo criado da seguinte maneira:

 @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(); } } 

Eu acho que a maneira mais simples de conseguir o que você quer é usar:

 ObjectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 

Isso adicionará informações de tipo no json serializado.

Aqui você é um exemplo em execução, que precisará adaptar ao 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()); 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); } } 

O object será serializado em algo semelhante a:

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

E será desserializado de volta corretamente, e a afirmação será aprovada.

Bytheway, existem mais maneiras de fazer isso, por favor, olhe para https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization para mais informações.

Eu espero que isso ajude.