在GSON上使用JsonDeserializer

时间:2015-10-15 09:31:35

标签: android json gson

我有一个可以处理多个JSON响应的模型。不过这是一个回应:

items: [
{
kind: "youtube#playlistItem",
etag: ""fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/jqbcTLu8tYm8b1FXGO14gNZrFG4"",
id: "PLUQ7I1jJqKB4lJarGcpWsP62l7iC06IkE2LDE0BxLe18",

与此相冲突(请注意具有不同类型的相同id字段。上述idString,另一个为Class):

items: [
{
kind: "youtube#searchResult",
etag: ""fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/hDIU49vmD5aPhKUN5Yz9gtljG9A"",
id: {
kind: "youtube#playlist",
playlistId: "PLh6xqIvLQJSf3ynKVEc1axUb1dQwvGWfO"
},

我想使用单个模型类阅读id字段。

这是我的模型Response类:

public class Response {
    private ArrayList<Item> items = new ArrayList<Item>();

这是我的模型Item类:

public class Item {
    private Id id;

//nested class inside Item
public class Id
{
    private String id;
    private String kind;
    private String playlistId;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getKind() {
        return kind;
    }

    public void setKind(String kind) {
        this.kind = kind;
    }

    public String getPlaylistId() {
        return playlistId;
    }

    public void setPlaylistId(String playlistId) {
        this.playlistId = playlistId;
    }
}

请注意,Id类位于Item类中。

这就是我使用registerTypeAdapter的方式:

 GsonBuilder gsonBuilder = new GsonBuilder();
            gsonBuilder.registerTypeAdapter(Response.class,
                    new JsonDeserializer<Item.Id>() {
                        @Override
                        public Item.Id deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
                            Item.Id result = new Item().new Id();

                            if(jsonElement.isJsonPrimitive() == false)
                            {
                                result.setKind(jsonElement.getAsJsonObject().get("kind").getAsString());
                                result.setPlaylistId(jsonElement.getAsJsonObject().get("playlistId").getAsString());
                                //return new Item.Id(jsonElement.getAsJsonObject().get("kind").getAsString(), jsonElement.getAsJsonObject().get("playlistId").getAsString());
                                return result;
                            }
                            else
                            {
                                result.setId(jsonElement.getAsString());
                                //return new Item.Id(jsonElement.getAsString());
                                return result;
                            }
                        }
                    });
            Gson gson = gsonBuilder.create();

            Response result = Response.success(
                    gson.fromJson(json, gsonClass),
                    HttpHeaderParser.parseCacheHeaders(response));

但是上面的代码会在此行中抛出java.lang.NullPointerException

if(jsonElement.isJsonPrimitive() == false)

我该怎么办? 这是使用registerTypeAdapter的正确方法吗?

感谢您的时间

2 个答案:

答案 0 :(得分:2)

您的主要问题似乎是您正在为Response类注册类型适配器,但是您正在提供处理JsonDeserializer类的Item.Id。您可以将完整Response反序列化,也可以将自己限制为Item甚至Item.Id

直接反序列化Item.Id(如您的问题中所述)的另一个问题是它是一个 - 静态内部类,它需要一个实例要实例化的父类(与new Item().new Id()一样)。如果你想保留它,我认为你必须手动反序列化整个Item,坦率地说,我认为没有任何理由不使Item.Id静态,因为它会简化问题。 / p>

这是我的静态版Item.Id

的解决方案
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Item.Id.class, new JsonDeserializer<Item.Id>() {
    @Override
    public Item.Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Item.Id id = new Item.Id();
        if (!json.isJsonPrimitive()) {
            JsonObject jsonObject = json.getAsJsonObject();
            id.setKind(jsonObject.get("kind").getAsString());
            id.setPlaylistId(jsonObject.get("playlistId").getAsString());
        } else {
            id.setId(json.getAsString());
        }
        return id;
    }
});

一些似乎对我有用的测试片段:

Gson gson = builder.create();
Response response = gson.fromJson("{\n" +
        "    \"items\": [\n" +
        "        {\n" +
        "            \"kind\": \"youtube#playlistItem\",\n" +
        "            \"etag\": \"fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/jqbcTLu8tYm8b1FXGO14gNZrFG4\",\n" +
        "            \"id\": \"PLUQ7I1jJqKB4lJarGcpWsP62l7iC06IkE2LDE0BxLe18\"\n" +
        "        }\n" +
        "    ]\n" +
        "}", Response.class);

Response response2 = gson.fromJson("{\n" +
        "    \"items\": [\n" +
        "        {\n" +
        "            \"kind\": \"youtube#searchResult\",\n" +
        "            \"etag\": \"fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/hDIU49vmD5aPhKUN5Yz9gtljG9A\",\n" +
        "            \"id\": {\n" +
        "                \"kind\": \"youtube#playlist\",\n" +
        "                \"playlistId\": \"PLh6xqIvLQJSf3ynKVEc1axUb1dQwvGWfO\"\n" +
        "            }\n" +
        "        }\n" +
        "    ]\n" +
        "}", Response.class);

如果您想保持Item.Id非静态,我认为您需要为Item编写反序列化器。还要记住,json元素可以不存在,但解析器应该仍然能够处理它。

答案 1 :(得分:1)

我很久以前就遇到了同样的问题,但我当时正在使用Json.Net,但是json概念(几乎)是相同的,所以我希望我能成功帮助。 我想它可能不起作用,但为什么不尝试注册Item类?我的意思是没有&#39; Item.Id&#39;因此,它的obious得到一个null。但是这个:gsonBuilder.registerTypeAdapter(Item.class,可能会失败,因为你没有明确地解析Item类(但它可能有效,我从来没有在Gson中尝试过。但是在Json.Net中,类似的方法可以正常工作。) 那么,你怎么能解决这个问题呢?我懒得写一个游侠,但你可以查看here并阅读here的surt摘要摘要(搜索Using the registerTypeAdapter()。 我希望我能帮忙。