[英]GSON Deserialize Map of Custom Object
我正在尝试使用 GSON 反序列化 Map<EventContext.Key, Object>。
我最初试图反序列化
System.out.println(eventContextMapSerialized);
Map<EventContext.Key, Object> deserializedMap = gson.fromJson(eventContextMapSerialized, HashMap.class);
LogisticService logisticService = (LogisticService) deserializedMap.get(EventContext.Key.LOGISTIC_SERVICE);
System.out.println(deserializedMap.get(EventContext.Key.LOGISTIC_SERVICE));
System.out.println(logisticService);
这给了我 output
[junit] {"LOGISTIC_SERVICE":{"serviceId":"dummy_id","serviceVersion":1,"serviceProviderRefId":{"id":"dummy_id"},"contract":{"invoiceCreator":"USPS","maxDaysToReceiveInvoice":180},"cancelled":false,"serviceConsumer":{"id":"SERVICE_CONSUMER_ID_1"},"serviceProvider":{"id":"USPS"},"plannedServiceTimePeriod":{"startTime":"Jan 1, 1970 5:30:00 AM"},"planner":"ATROPS"},"PLATFORM_SERVICE_ID":"TestPlatformServiceId"}
[junit] null
[junit] null
因此,即使序列化字符串包含 LogisticService 类型的 object,当我尝试获取它时,我也会得到 null。
因此,我尝试使用fromJson
的重载方法,该方法将 Type 作为参数。
Type type = new TypeToken<Map<EventContext.Key, Object>>(){}.getType();
Map<EventContext.Key, Object> eventContextMapDeserialized = gson.fromJson(eventContextMapSerialized, type);
System.out.println("Event Context Map Deserialized is : " + eventContextMapDeserialized);
System.out.println(eventContextMapDeserialized.get(EventContext.Key.LOGISTIC_SERVICE).getClass());
LogisticService logisticServiceFromMap = (LogisticService) eventContextMapDeserialized.get(EventContext.Key.LOGISTIC_SERVICE);
System.out.println("Logistic Service from Event Context Map : " + logisticServiceFromMap);
System.out.println("Direct Logistic Service : " + eventContextDeserialized.get(EventContext.Key.LOGISTIC_SERVICE));
这给了output,
[junit] Event Context Map Deserialized is : {LOGISTIC_SERVICE={serviceId=dummy_id, serviceVersion=1.0, serviceProviderRefId={id=dummy_id}, contract={invoiceCreator=USPS, maxDaysToReceiveInvoice=180.0}, cancelled=false, serviceConsumer={id=SERVICE_CONSUMER_ID_1}, serviceProvider={id=USPS}, plannedServiceTimePeriod={startTime=Jan 1, 1970 5:30:00 AM}, planner=ATROPS}, PLATFORM_SERVICE_ID=TestPlatformServiceId}
[junit] class com.google.gson.internal.LinkedTreeMap
[junit] Testcase: testPayloadDeserialize took 10.812 sec
[junit] Caused an ERROR
[junit] com.google.gson.internal.LinkedTreeMap cannot be cast to com.amazon.transportation.tfs.contapservice.sdk.model.LogisticService
[junit] java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.amazon.transportation.tfs.contapservice.sdk.model.LogisticService
基本上,在我尝试施放的地方炸毁
(LogisticService) eventContextMapDeserialized.get(EventContext.Key.LOGISTIC_SERVICE);
我无法弄清楚为什么在第一种情况下 output 是 Null 而在第二种情况下,即使在给出类型之后,它仍然会崩溃。
正如评论中所指出的,当您反序列HashMap.class
或TypeToken<Map<EventContext.Key, Object>>
Gson 时无法知道您期望的值类型。 Instead it sees that the data contains a JSON object and deserializes it as Java Map
by default (Gson's internal Map
implementation is LinkedTreeMap
).
由于看起来您正在处理异构 map,因此您需要采用另一种方法。 以下解决方案都有其优点和缺点,这取决于您的用例,哪一种最适合。
您可以创建一个单独的 class 到 model Map
,例如:
class EventData {
// Use Gson's @SerializedName annotation to not use the field name
@SerializedName("LOGISTIC_SERVICE")
public LogisticService logisticService;
}
Gson gson = new Gson();
EventData eventData = gson.fromJson(EventData.class);
LogisticService logisticService = eventData.logisticService;
这个解决方案可能是最简单的一个。 缺点是您不能保留任何 JSON object 成员,这些成员未部分建模为 model ZA2F21ED4F8EBC26CBBDC 的字段。
您可以首先将 JSON 数据反序列化为JsonObject
,这是 Gson 的 class 代表 JSON 文档树。 例如,这可以使用JsonParser
来完成。 之后,您使用JsonObject.getAsJsonObject(String)
提取相关成员并使用Gson.fromJson(JsonElement, ...)
对其进行反序列化。
这样做的好处是,您也可以从该JsonObject
访问其他成员,例如,如果稍后需要它们。 但是,缺点是这需要更多的 memory,因为它必须将完整的 JSON 文档保存为 memory 中的JsonObject
,但这可能取决于您的用例或您的数据。
JsonReader
一种解决方案可能是直接使用JsonReader
,然后根据 JSON object 成员名称分别解析它们:
Gson gson = new Gson();
LogisticService logisticService = null;
JsonReader jsonReader = new JsonReader(json);
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (name.equals(EventContext.Key.LOGISTIC_SERVICE.name()) {
if (logisticService != null) {
// Duplicate member -> malicious or malformed JSON, throw exception
...
}
logisticService = gson.fromJson(jsonReader, LogisticService.class);
}
else {
// Skip value or parse it in a different way
jsonReader.skipValue();
}
}
jsonReader.endObject();
或者,当此数据是较大 JSON 文档的一部分时,您还可以将此代码放入TypeAdapterFactory
并使用您在其上注册工厂的GsonBuilder
创建Gson
实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.