簡體   English   中英

GSON 反序列化自定義 Object 的 Map

[英]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.classTypeToken<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,因此您需要采用另一種方法。 以下解決方案都有其優點和缺點,這取決於您的用例,哪一種最適合。

分離 model class

您可以創建一個單獨的 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 的字段。

解析為 DOM,然后解析所需的成員

您可以首先將 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM