如何使用gson反序列化base64编码的json数据

时间:2018-01-23 10:16:26

标签: json base64 gson

我有一个像这样的json:

{code:1, message:"ok", data:"W3tpZDoxLCBuYW1lOiJUb20ifSx7aWQ6MiwgbmFtZToiSmFjayJ9LHtpZDozLCBuYW1lOiJMdWNpYSJ9XQ=="}

,只有数据使用base64编码,真实数据是:

[{id:1, name:"Tom"},{id:2, name:"Jack"},{id:3, name:"Lucia"}]

。如何使用gson一步反序化这个json?

1 个答案:

答案 0 :(得分:1)

Gson在这里提出了几个选择,但以下似乎是最短的选择。请考虑以下ResponseUser类:

final class Response<T> {

    @SerializedName("code")
    final int code = Integer.valueOf(0);

    @SerializedName("message")
    final String message = null;

    @SerializedName("data")
    @JsonAdapter(Base64TypeAdapterFactory.class)
    final T data = null;

}

final class User {

    final int id = Integer.valueOf(0);
    final String name = null;

    @Override
    public String toString() {
        return id + ":" + name;
    }

}
上面的

@JsonAdapter(Base64TypeAdapterFactory.class)告诉Gson为给定字段选择一个特殊类型的适配器。 此类型适配器将负责Base64解码,并且在反序列化期间可以使用类型令牌来专门化实际类型。

final class Base64TypeAdapterFactory
        implements TypeAdapterFactory {

    // Gson can instantiate this one itself, no need to expose it
    private Base64TypeAdapterFactory() {
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        final TypeAdapter<String> stringTypeAdapter = gson.getAdapter(String.class);
        final TypeAdapter<T> dataTypeAdapter = gson.getAdapter(typeToken);
        return Base64TypeAdapter.of(stringTypeAdapter, dataTypeAdapter);
    }

    private static final class Base64TypeAdapter<T>
            extends TypeAdapter<T> {

        private static final Decoder base64Decoder = Base64.getDecoder();

        private final TypeAdapter<String> stringTypeAdapter;
        private final TypeAdapter<T> dataTypeAdapter;

        private Base64TypeAdapter(final TypeAdapter<String> stringTypeAdapter, final TypeAdapter<T> dataTypeAdapter) {
            this.stringTypeAdapter = stringTypeAdapter;
            this.dataTypeAdapter = dataTypeAdapter;
        }

        static <T> TypeAdapter<T> of(final TypeAdapter<String> stringTypeAdapter, final TypeAdapter<T> dataTypeAdapter) {
            return new Base64TypeAdapter<>(stringTypeAdapter, dataTypeAdapter)
                    .nullSafe(); // Just let Gson manage nulls itself. It's convenient
        }

        @Override
        public void write(final JsonWriter jsonWriter, final T value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public T read(final JsonReader jsonReader)
                throws IOException {
            // Decode the payload first as a Base64-encoded message
            final byte[] payload = base64Decoder.decode(stringTypeAdapter.read(jsonReader));
            try ( final JsonReader payloadJsonReader = new JsonReader(new InputStreamReader(new ByteArrayInputStream(payload))) ) {
                // And tell Gson to not refuse unquoted property names
                payloadJsonReader.setLenient(true);
                return dataTypeAdapter.read(payloadJsonReader);
            } catch ( final EOFException ignored ) {
                return null;
            }
        }

    }

}

现在您可以轻松测试它:

final Response<List<User>> response = gson.fromJson(..., new TypeToken<Response<List<User>>>() {
}.getType());
System.out.println(response.code);
System.out.println(response.message);
System.out.println(response.data);

输出:

1
ok
[1:Tom, 2:Jack, 3:Lucia]