Gson 非常棒,它确实允许应用自定义反序列化策略,或者实现对用户不太友好的 JSON 结构的适配器。假设您可以将以下自定义映射用于搜索查询结果:
final class Suggestions {
final String query;
final List<String> suggestions;
Suggestions(final String query, final List<String> suggestions) {
this.query = query;
this.suggestions = suggestions;
}
}
编写自定义JsonDeserializer(认为它只是一个 JSON 到 Java 对象/值转换器),您可以在其中定义如何解析给定的 JSON 有效负载并将其转换为 Suggestions 类实例:
final class SuggestionsJsonDeserializer
implements JsonDeserializer<Suggestions> {
private static final JsonDeserializer<Suggestions> suggestionsJsonDeserializer = new SuggestionsJsonDeserializer();
private static final Type listOfStringsType = new TypeToken<List<String>>() {
}.getType();
private SuggestionsJsonDeserializer() {
}
static JsonDeserializer<Suggestions> getSuggestionsJsonDeserializer() {
return suggestionsJsonDeserializer;
}
@Override
public Suggestions deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
if ( !jsonElement.isJsonArray() ) {
throw new JsonParseException("The given JSON is not an array");
}
final JsonArray jsonArray = jsonElement.getAsJsonArray();
final int length = jsonArray.size();
if ( length != 2 ) {
throw new JsonParseException("The given JSON array length is " + length);
}
final JsonElement e0 = jsonArray.get(0);
final JsonElement e1 = jsonArray.get(1);
final String query;
final List<String> suggestions;
if ( e0.isJsonPrimitive() && e1.isJsonArray() ) {
// If the JSON array is [query, suggestions]
query = e0.getAsJsonPrimitive().getAsString();
suggestions = context.deserialize(e1.getAsJsonArray(), listOfStringsType);
// e1.getAsJsonArray() call is unnecessary because the context would throw an exception if it would be not an array
// But just make it explicit and "more symmetric" to the object destructuring around
// Another way might be not delegating the string list parsing to context, but building a string list out of the JSON array of strings manually
} else if ( e0.isJsonArray() && e1.isJsonPrimitive() ) {
// If the JSON array elements are swapped like [suggestions, query]
query = e1.getAsJsonPrimitive().getAsString();
suggestions = context.deserialize(e0.getAsJsonArray(), listOfStringsType);
} else {
throw new JsonParseException("Unexpected JSON array structure");
}
return new Suggestions(query, suggestions);
}
}
下一步是让 Gson 了解您的映射及其 JSON 反序列化器对:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(Suggestions.class, getSuggestionsJsonDeserializer())
.create();
在没有改造的情况下测试它
final Suggestions suggestions = gson.fromJson(JSON, Suggestions.class);
out.println(suggestions.query);
out.println(suggestions.suggestions);
将输出:
足球
【足球、足球技巧、足球藤蔓、足球失败、足球经理2017、足球挑战、足球尊重、足球经理2017下载、足球工厂、足球日报】
为了让 Retrofit 知道您的自定义 Gson 实例,您只需在 Retrofit.Builder 中注册它,对于 Retrofit 2 使用 .addConverterFactory(GsonConverterFactory.create(gson)),或者对于 Retrofit 1 使用 .setConverter(new GsonConverter(gson)) (如果我没记错的话) .