杰克逊:反序列化为Map< String,Object>每个值的类型正确 [英] Jackson: Deserialize to a Map<String, Object> with correct type for each value

查看:219
本文介绍了杰克逊:反序列化为Map< String,Object>每个值的类型正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一堂课,看起来像下面的

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.
   ...
}

我希望能够与Jackson进行往返,从对象到JSON再返回.我可以很好地序列化对象并接收以下输出:

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
    }
}

我遇到的问题是,由于序列化映射中的值没有任何类型信息,因此无法正确地反序列化它们.例如,在上面的示例中,应将enumValue1反序列化为枚举值,而应反序列化为字符串.我已经看到了基于各种事物的类型的示例,但是在我的场景中,我不知道类型是什么(它们将是用户生成的对象,我事先不会知道),所以我需要能够使用键值对序列化类型信息.我如何用杰克逊来做到这一点?

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?

为了记录,我使用的是Jackson 2.4.2版.我用来测试往返的代码如下:

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

由于这是基于Spring的项目,因此将按以下方式创建映射器:

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

推荐答案

我认为实现所需目标的最简单方法是使用:

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

ObjectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

这将在序列化的json中添加类型信息.

This will add type information in the serialized json.

这是一个正在运行的示例,您需要适应Spring:

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.

此外,还有更多方法可以执行此操作,请查看 https://github. com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization 了解更多信息.

Bytheway there are more ways of doing this, please look at https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization for more info.

我希望它会有所帮助.

这篇关于杰克逊:反序列化为Map&lt; String,Object&gt;每个值的类型正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆