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

Min*_* Gu 4 base64 json gson

我有一个像这样的 json:

{code:1, message:"ok", data:"W3tpZDoxLCBuYW1lOiJUb20ifSx7aWQ6MiwgbmFtZToiSmFjayJ9LHtpZDozLCBuYW1lOiJMdWNpYSJ9XQ=="}
Run Code Online (Sandbox Code Playgroud)

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

[{id:1, name:"Tom"},{id:2, name:"Jack"},{id:3, name:"Lucia"}]
Run Code Online (Sandbox Code Playgroud)

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

Lyu*_*riv 6

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

@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;
            }
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

现在您可以轻松测试它:

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

输出:

1
ok
[1:Tom, 2:Jack, 3:Lucia]
Run Code Online (Sandbox Code Playgroud)