如何为嵌入式对象编写GSON自定义反序列化器,有两种可能的类型

Mar*_*arc 5 java serialization json gson

我在尝试反序列化java对象时遇到问题,因为对象内的字段("info")可能是两种可能的类型之一:ArrayList或者只是String.Here是我到目前为止所做的:

首先,创建类Base:

public class Base {
}
Run Code Online (Sandbox Code Playgroud)

接下来创建子类:

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

public class BadInfo extends Base {
    public String info;
}
Run Code Online (Sandbox Code Playgroud)

所以现在我想解析我的JSON,它是Base对象的ArrayList(即每个对象是ArrayList或String的对象的ArrayList):

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

我知道为了这个工作,我必须写一个自定义的反序列化器.解串器看起来像这样:

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

正如您所看到的,我不知道如何尝试反序列化每个子类型并返回有效的类型.有人知道怎么做吗?

我认为它看起来像这样:

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

根据GSON,我不能在传入的json上使用context.deserialize:在指定对象上调用默认的反序列化.永远不应该在作为JsonDeserializer.deserialize(JsonElement,Type,JsonDeserializationContext)方法的参数接收的元素上调用它.这样做会导致无限循环,因为Gson会再次调用自定义反序列化器.

那我该怎么做?

Jon*_*han 7

没有文档读取(强调我的):

...你永远不应该在相同的类型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);
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以JsonDeserializer通过修改超类来完全绕过自定义.拉起infoObject,例如:

public class Base {
    public Object info;
}
Run Code Online (Sandbox Code Playgroud)

将允许Gson适当地反序列化该值.


ToY*_*nos 5

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该解决方案是工作正常为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

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);
Run Code Online (Sandbox Code Playgroud)

它打印:

2 test [test, test, test]