如何迭代JsonReader两次?

时间:2017-12-03 23:34:08

标签: android gson

我面临以下问题:我有这样的json

{
    "type": "objectType",
    "body": {
         //could be one of five different object types
    }
}

"body"可能是一组固定类型,因此我尝试实现自定义TypeAdapter:

@Override
public MyObject read(final JsonReader pJsonReader) throws IOException {
    if (pJsonReader.peek() == JsonToken.NULL) {
        pJsonReader.nextNull();
        return null;
    }

    pJsonReader.beginObject();
    String type = null;

    while (pJsonReader.hasNext()) {
        final String fieldName = pJsonReader.nextString();

        if (pJsonReader.peek() == JsonToken.NULL) {
            pJsonReader.nextNull();
            continue;
        }

        switch (fieldName) {
            case TYPE: {
                tyoe = mStringTypeAdapter.read(pJsonReader);
                break;
            }
            case BODY: {
                body = //I need to choose a particular TypeAdapter basing on type field
            }
            default: {
                pJsonReader.skipValue();
            }
        }
    }

    pJsonReader.endObject();

    return MyObject(type, body);
}

问题是我需要根据"body""type"选择TypeAdapter所以我需要以某种方式复制JsonReader,并在找到"type"值时再次迭代它。 知道我该怎么做吗?

1 个答案:

答案 0 :(得分:0)

如果您要控制JSON的结构,则最好嵌套 body ,这样您始终可以首先读取 type

但是,如果您无法更改JSON的结构,则可以使用JsonParser创建内存中的表示形式,然后从中读取相应的 type 适配器:

public class MyObjectTypeAdapter extends TypeAdapter<MyObject> {
    @Override
    public void write(JsonWriter out, MyObject value) throws IOException {
        // You will have to implement this in case you are
        // also writing JSON data
        throw new UnsupportedOperationException();
    }
    
    @Override
    public MyObject read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }

        String type = null;
        JsonElement body = null;

        in.beginObject();
        while (in.hasNext()) {
            String fieldName = in.nextString();

            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                continue;
            }

            switch (fieldName) {
                case "TYPE": {
                    type = in.nextString();
                    break;
                }
                case "BODY": {
                    body = JsonParser.parseReader(in);
                    break;
                }
                default: {
                    in.skipValue();
                }
            }
        }
        in.endObject();

        // Get the corresponding adapter for `type`
        // Possibly also have to create this MyObjectTypeAdapter using a
        // TypeAdapterFactory to be able to use Gson for the adapter lookup
        TypeAdapter<?> bodyAdapter = ...
        
        return new MyObject(type, bodyAdapter.fromJsonTree(body));
    }
}

这不会那么有效,但是如果 body 没那么复杂,这应该不是大问题。