[英]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.