繁体   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