我在尝试反序列化Java对象时遇到了麻烦,因为对象内部的字段(“info”)可以是两种可能的类型之一:ArrayList或只是String。这是我到目前为止所做的:

首先,创建类Base:

public class Base {
}

接下来创建子类:
public class GoodInfo extends Base {
    public ArrayList<MyCustomObject> info;
}

public class BadInfo extends Base {
    public String info;
}

因此,现在我想解析我的JSON,它是基础对象的ArrayList(即对象的ArrayList,其中每个对象是ArrayList或String):
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会依次再次调用自定义解串器。

那么我该怎么做呢?

最佳答案

documentation reads(重点是我的):

...您永远不要在传递相同类型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适当地反序列化该值。

08-04 17:36