簡體   English   中英

如何為嵌入式對象編寫GSON自定義反序列化器,有兩種可能的類型

[英]How to write GSON custom deserializer for embedded object with two possible types

我在嘗試反序列化java對象時遇到問題,因為對象內的字段(“info”)可能是兩種可能類型之一:ArrayList或者只是String.Here是我到目前為止所做的:

首先,創建類Base:

public class Base {
}

接下來創建子類:

public class GoodInfo extends Base {
    public ArrayList<MyCustomObject> info;
}

public class BadInfo extends Base {
    public String info;
}

所以現在我想解析我的JSON,它是Base對象的ArrayList(即每個對象是ArrayList或String的對象的ArrayList):

Type listOfBase = new TypeToken<ArrayList<Base>>(){}.getType();
ArrayList<Base> resp=gson.fromJson(jsonText, listOfBase);

我知道為了這個工作,我必須寫一個自定義的反序列化器。 解串器看起來像這樣:

private class MyCustomDeserializer implements JsonDeserializer<DateTime> {
    public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
  throws JsonParseException {
        // WHAT DO I DO HERE?
    }
}

正如您所看到的,我不知道如何嘗試反序列化每個子類型並返回有效的類型。 有人知道怎么做嗎?

我認為它看起來像這樣:

private class MyCustomDeserializer implements JsonDeserializer<DateTime> {
    public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
  throws JsonParseException {
        try {
            GoodInfo goodInfo=SOMEHOW TRY TO DESERIALIZE json INTO A GoodInfo object
            return goodInfo;
        } catch {
            //
        }
        try {
            BadInfo badInfo=SOMEHOW TRY TO DESERIALIZE json INTO A BadInfo object
            return badInfo;
        } catch {
            throw new JsonParseException("Could not deserialize");
        }
    }
}

根據GSON,我不能在傳入的json上使用context.deserialize:在指定對象上調用默認的反序列化。 永遠不應該在作為JsonDeserializer.deserialize(JsonElement,Type,JsonDeserializationContext)方法的參數接收的元素上調用它。 這樣做會導致無限循環,因為Gson會再次調用自定義反序列化器。

那我該怎么做?

沒有文檔讀取 (強調我的):

...你永遠不應該在傳遞json的相同類型上調用它,因為這將導致無限循環...

只要類型不同,調用context.deserialize(...)就完全沒問題了。

您可以使用json檢查info字段並根據元素類型采取適當的操作,而不是在反序列化器中捕獲異常,例如:

public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    final JsonElement elem = json.getAsJsonObject()
                                 .get("info");
    if (elem.isJsonArray()) {
        return context.deserialize(json, GoodInfo.class);
    }
    return context.deserialize(json, BadInfo.class);
}

或者,您可以通過修改超類來完全繞過自定義JsonDeserializer info字段作為Object拉出,例如:

public class Base {
    public Object info;
}

將允許Gson適當地反序列化該值。

class MyCustomDeserializer implements JsonDeserializer<Base>
{
    public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
    {
        try
        {
            return context.deserialize(json, GoodInfo.class);
        }
        catch (JsonParseException e)
        {
            return context.deserialize(json, BadInfo.class);
        }
    }
}

此解決方案工作正常,因為GoodInfoBadInfo的類型與Base的GSON類型不同,因為從對象的角度來看, GoodInfoBadInfo實例 Base實例。

考慮到這兩個類都有toString()實現:

class GoodInfo extends Base
{
    public ArrayList<String> info;

    public String toString()
    {
        return info.toString();
    }
}

class BadInfo extends Base
{
    public String info;

    public String toString()
    {
        return info;
    }
}

測試:

Type listOfBase = new TypeToken<ArrayList<Base>>(){}.getType();
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Base.class, new MyCustomDeserializer());
Gson gson = gsonBuilder.create();
ArrayList<Base> resp = gson.fromJson("[{\"info\": \"test\"}, {\"info\": [\"test\", \"test\", \"test\"]}]", listOfBase);
System.out.println(resp.size());
for (Object o : resp) System.out.println(o);

它打印:

2 test [test, test, test]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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