如何将带有类型信息的json反序列化为Map<String, Object>?

问题描述 投票:0回答:1

我有课

SomeClass
:

public class SomeClass {
    public String someString = "SOME-STRING-VALUE";

    public Date someDate = new Date();
}

我的目标是创建一个

Map<String, Object>
,其中包含
SomeClass
的成员名称作为键,其值作为给定
SomeClass

实例的映射中的值

为此,我使用 Jackson,如下所示:

SomeClass someObject = new SomeClass();

ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(someObject);    // serialize object
System.out.println(jsonString);    // {"someString":"SOME-STRING-VALUE","someDate":1500138786720}

Map<String, Object> objectMap = mapper.readValue(jsonString, Map.class);    // deserialize back to Map instead of SomeClass
objectMap.forEach((k, v) -> System.out.println(k + " : " + v + " : " + v.getClass()));
// This prints:
// someString : SOME-STRING-VALUE : class java.lang.String
// someDate : 1500138786720 : class java.lang.Long

因此,我使用对象映射器将对象序列化为

jsonString
,然后为了创建所需的映射,我将
jsonString
反序列化回
Map

这里的问题是

Date
字段被序列化为原始 long 值,而在反序列化回来时,它被反序列化为
Long
而不是
Date
,因为我将其反序列化为
Object
。如果我一直将反序列化回
SomeClass
,则
Long
值将转换为相关的
Date
值。但就我而言,在反序列化时,
mapper
不知道反序列化之前
someDate
的实际类型是什么,因此
someDate
Long
中被反序列化为
objectMap
本身。

似乎确实有一种方法可以让映射器在序列化之前知道

jsonString
中给定字段的类型,方法是使用
杰克逊多态类型处理
将类型信息嵌入到jsonString中。为此,我在编写
jsonString
之前启用了默认输入:

mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

我现在得到的

jsonString
是:

["some.package.name.here.SomeClass",{"someString":"SOME-STRING-VALUE","someDate":["java.util.Date",1500140185993]}]

因此

jsonString
现在包含
someDate
字段的类型。但我很难将其中包含类型信息的
jsonString
读回我的
objectMap
。我遇到异常:

java.lang.IllegalArgumentException:类 some.package.name.here.SomeClass 不是[地图类型的子类型; class java.util.Map, [简单类型, 类 java.lang.Object] -> [简单类型,类 java.lang.Object]]

我是否需要将

Map<String, Object> objectMap = mapper.readValue(jsonString, Map.class);
行更改为其他内容,让
mapper
知道它要读取的字符串不是普通字符串,而是嵌入了类型信息的字符串。映射器不应该已经知道这一点吗,因为我们用来读取
jsonString
的映射器对象与编写它的映射器对象完全相同?

我发现的所有示例都遵循继承层次结构示例,在阅读时它们只会传递 BaseClass,但我无法弄清楚我应该为我的情况做什么。

如何将

someDate
字段从
Date
转换回
Long
,同时将其放入具有
Object
类型值的地图中?

java serialization jackson polymorphism deserialization
1个回答
0
投票

带有类型参考

Map<String, Date> map = mapper.readValue(json, new TypeReference<Map<String, Date>>() {});

您可以为映射中的所有值提供类型,但实际上对于具有不同类型属性的映射,您的 SomeClass 提供了用于反序列化此映射的结构和必要的类型信息,因此我只需使用 SomeClass 进行反序列化,然后如果您需要映射,则创建结果对象属性的映射,例如与

Map<String, Object> map = new HashMap<>();
    Field[] fields = object.getClass().getDeclaredFields();

    for (Field field: fields) {
        field.setAccessible(true);
        map.put(field.getName(), field.get(object));
    } 
© www.soinside.com 2019 - 2024. All rights reserved.