【问题标题】:GSON - parse specific JSONGSON - 解析特定的 JSON
【发布时间】:2017-02-07 23:19:56
【问题描述】:

如何在 Retrofit (GSON) 中解析这个?

["football",["football","football skills","football vines","football fails","football manager 2017","football challenge","football respect","football manager 2017 download","football factory","football daily"]]

这是一个包含一个字符串和另一个数组的数组。 没有对象,只有数组。 如何在模型中表示?

这是服务器: http://suggestqueries.google.com/complete/search?client=firefox&ds=yt&q=Query

我尝试使用 JSON 到 POJO,但它什么也没返回。

【问题讨论】:

标签: android json gson retrofit2


【解决方案1】:

@MoQ 是对的,json 是错误的,因为它不是一个对象。你需要把它包裹在一个里面,比如 {"list":["football",["football","football skills","football vines","football failed","football manager 2017","football challenge", 《足球尊重》、《足球经理2017下载》、《足球工厂》、《足球日报》]]}

它被称为 JavaScript Object 表示法。

【讨论】:

  • 我同意你的观点,但是服务器返回了这个,所以我试图以某种方式解决这个问题。服务器:suggestqueries.google.com/complete/…
  • 好的,在这种情况下,您应该改写问题。您没有得到 json,但希望解析器足够宽松以将其反序列化为对象。
  • 但是每个 json 验证器都说它是有效的 json。它是什么,如果不是 json?
  • 有趣。我浏览了 RFC,似乎没有任何内容禁止这种结构。很高兴知道,谢谢。但是,您如何将其映射到面向对象的环境?我的方法仍然是在 json 到达解析器之前对其进行转换。
  • 我虽然可以找到一些解决方法。我知道不容易映射。另外,我使用 JSONArray 轻松解析了这个,非常简单。
【解决方案2】:

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)) (如果我没记错的话) .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 2011-02-12
    相关资源
    最近更新 更多