我有一个类似于下面的类

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

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

作为记录,我使用的是杰克逊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();
    }
}

推荐答案

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

}

该对象将被序列化为类似于以下内容的内容:

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

将被正确反序列化,断言将通过.

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

我希望这会有帮助.

Json相关问答推荐

使用相同的密钥值来命名Json并使用Jolt重命名密钥

Jolt将键和值转换为单独的数组集

盒子图显示不正确

集成wix.comstore API|变音符号问题

将PostgreSQL转换为JSON对象

Jolt-在数组列表中插入新的字段

如何在Android中解析带有动态键和可变对象名称的改装JSON响应?

规范化JSON数据

如何避免解析 ISuperObject 类型字段中的 json 对象

Golang jsonrpc2 服务器在哪里监听?

条件性构建/修改嵌套对象数组

基于JQ中另一个对象的值 Select 对象

我如何将 JSON 格式与 flutter 一起使用?帮助使用 Gamebanana api

判断golang中解析的json响应中是否存在所需的json键(不是值)

jq搜索特定字符串并输出对应的父值

现代浏览器一次可以处理多少个 HTML 元素?

JSON.NET 中特定对象的自定义转换

将 JSON 数据导入 Google 表格

将错误消息作为 JSON 对象发送

如何转换为 D3 的 JSON 格式?