使用Gson反序列化字符串中的JSON

时间:2017-04-17 18:08:49

标签: android gson

我正在使用GsonConverter的Retrofit 2。问题是我有这样的回应:

"responseData": {
   "data": "<json array>"
}

正如您所看到的,其中一个参数是JSON数组,但它是一个字符串。我应该使用TypeAdapter并覆盖readwrite方法吗?如果是这样,你能告诉我如何做到这一点吗?

1 个答案:

答案 0 :(得分:0)

  

正如您所看到的,其中一个参数是JSON数组,但它是一个字符串。

如果响应生成器在您的控制之下,您肯定应该更改响应格式(格式良好和性能都很好(Gson不允许将字符串文字读/写为原始值)。)

  

我应该使用TypeAdapter并覆盖readwrite方法吗?

如果无法控制服务器响应,则必须实现仅使用read方法的自定义类型适配器。要与该响应格式保持一致,您可以定义以下自定义映射:

final class Response<T> {

    final ResponseData<T> responseData = null;

}
final class ResponseData<T> {

    // This is where we're telling Gson to apply the special read strategy, not to all types
    @JsonAdapter(RawJsonTypeAdapterFactory.class)
    final T data = null;

}

如您所见,您只需将自定义类型适配器绑定到特定字段。尽管JsonAdapter注释也接受TypeAdapter个类,但您无法直接绑定TypeAdapter,因为您需要GsonType个实例。

final class RawJsonTypeAdapterFactory
        implements TypeAdapterFactory {

    // Gson will instantiate it itself without any issues   
    private RawJsonTypeAdapterFactory() {
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        // No additional checks here, we're assuming the necessary fields are properly annotated
        final Type type = typeToken.getType();
        return new TypeAdapter<T>() {
            @Override
            public void write(final JsonWriter out, final T value) {
                throw new UnsupportedOperationException();
            }

            @Override
            public T read(final JsonReader in)
                    throws IOException {
                return gson.fromJson(in.nextString(), type);
            }
        }.nullSafe(); // And making the type adapter null-safe
    }

}

现在JSON文档就像

{
    "responseData": {
        "data": "[1,2,3]"
    }
}

可以在普通Java中轻松解析:

private static final Type intArrayResponseType = new TypeToken<Response<int[]>>() {
}.getType();

private static final Gson gson = new Gson();

...

try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43456942.class, "stringified.json") ) {
    final Response<int[]> response = gson.fromJson(jsonReader, intArrayResponseType);
    System.out.println(Arrays.toString(response.responseData.data));
}

输出:

  

[1,2,3]

您的Retrofit绑定服务可能有一个声明此方法的方法(因为Retrofit非常智能,可以将Call参数化传递给基础Gson转换器,所以没有必要的类型标记):

Call<Response<int[]>> getIntArray();