【问题标题】:Gson not properly serializing JSON into POJO with RetrofitGson 没有使用 Retrofit 正确地将 JSON 序列化为 POJO
【发布时间】:2015-07-03 20:36:18
【问题描述】:

我从 NYTimes TopStories API 返回以下 JSON;

{
"status": "OK",
"copyright": "Copyright (c) 2015 The New York Times Company. All Rights Reserved.",
"last_updated": "2015-07-03T01:25:02-05:00",
"num_results": 21,
"results": [
    {
        "section": "World",
        "subsection": "Africa",
        "title": "Tunisia Jihadist Died in Libya Strike, U.S. Official Says",
        "abstract": "Seifallah Ben Hassine, one of Osama bin Laden’s top lieutenants and Tunisia’s most wanted jihadist, was killed in an American airstrike in Libya last month, a senior United States official said.",
        "url": "http://www.nytimes.com/2015/07/03/world/africa/jihadist-from-tunisia-died-in-strike-in-libya-us-official-says.html",
        "byline": "By CARLOTTA GALL and ERIC SCHMITT",
        "item_type": "Article",
        "updated_date": "2015-07-02T21:18:07-5:00",
        "created_date": "2015-07-02T21:18:10-5:00",
        "published_date": "2015-07-03T04:00:00-5:00",
        "material_type_facet": "News",
        "kicker": "",
        "des_facet": [
            "Terrorism",
            "Defense and Military Forces"
        ],
        "org_facet": "",
        "per_facet": [
            "Hassine, Seifallah Ben",
            "bin Laden, Osama"
        ],
        "geo_facet": [
            "Tunisia",
            "Libya"
        ],
        "multimedia": ""
    }
]
}

NYTimes 返回此 JSON,标题为 text/json,我不确定这是否对此有任何影响。

我正在使用 Retrofit,并且我的 onSuccess 方法在回调中永远不会到达。我有这样声明的模型类:

主模型类

public class TopStories {

    @SerializedName("status")
    private String mStatus;
    public String getStatus() {
        return mStatus;
    }

    @SerializedName("copyright")
    private String mCopyright;
    public String getCopyright() {
        return mCopyright;
    }

    @SerializedName("last_updated")
    private String mLastUpdated;
    public String getLastUpdated() {
        return mLastUpdated;
    }

    @SerializedName("num_results")
    private int mNumResults;
    public int getNumResults() {
        return mNumResults;
    }

    @SerializedName("results")
    private List<Result> mResults;
    public List<Result> getResults() {
        return mResults;
    }

}

结果模型类

public class Result {

    @SerializedName("section")
    private String mSection;
    public String getSection() {
        return mSection;
    }

    @SerializedName("subsection")
    private String mSubSection;
    public String getSubSection() {
        return mSubSection;
    }

    @SerializedName("title")
    private String mTitle;
    public String getTitle() {
        return mTitle;
    }

    @SerializedName("abstract")
    private String mAbstract;
    public String getAbstract() {
        return mAbstract;
    }

    @SerializedName("url")
    private String mUrl;
    public String getUrl() {
        return mUrl;
    }

    @SerializedName("byline")
    private String myByLine;
    public String getMyByLine() {
        return myByLine;
    }

    @SerializedName("item_type")
    private String mItemType;
    public String getItemType() {
        return mItemType;
    }

    @SerializedName("updated_date")
    private String mUpdatedDate;
    public String getUpdatedDate() {
        return mUpdatedDate;
    }

    @SerializedName("created_date")
    private String mCreatedDate;
    public String getCreatedDate() {
        return mCreatedDate;
    }

    @SerializedName("multimedia")
    private List<Multimedia> mMultimedia;
    public List<Multimedia> getMultimedia() {
        return mMultimedia;
    }

}

你明白了,我有另一个"multimedia" 的模型类,好的继续我创建了一个RestAdapter,如下所示:

private NYTimesService() {

    mAsyncRestAdapter = new RestAdapter.Builder()
            .setEndpoint(API_URL)
            .setRequestInterceptor(new RequestInterceptor() {
                @Override
                public void intercept(RequestFacade request) {
                    request.addEncodedQueryParam("api-key", API_KEY);
                }
            })
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .build();
}

我有一个这样的 API 接口:

public interface ITopStories {

    @Headers("Content-Type: text/json")
    @GET("/topstories/v1/home.json")
    void getTopStories(Callback<TopStories> callback);

}

我的Callback&lt;T&gt; 是这样定义的:

@Subscribe
public void onLoadTopStories(LoadTopStories loadTopStories) {
    Log.d(TAG, "onLoadTopStories");
    Callback<TopStories> callback = new Callback<TopStories>() {
        @Override
        public void success(TopStories topStories, Response response) {
            Log.d(TAG, "onSuccess");
            mBus.post(new LoadedTopStories(topStories));
        }

        @Override
        public void failure(RetrofitError error) {

        }
    };
    sClient.getTopStories(callback);
}

Log.d(TAG, "onLoadTopStories"); 可以正常调用,问题是永远无法到达 Log.d(TAG, "onSuccess");。这里有什么问题?

一些注意事项:

  • "results" 可以是数组,也可以是空字符串
  • 与“多媒体”相同
  • 让我感到困惑的是.getCopyright()getStatus() 从来没有在TopStories.java 开头序列化

另外RetrofitGET 请求也没有问题,并且可以正确启动它:

更新

onFailure 添加了日志语句,我得到以下信息:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: 应为 BEGIN_ARRAY,但在第 1 行第 1 列 10819 路径 $.results[4].multimedia 处为 STRING

多媒体可以是数组或空字符串

"multimedia": [
            {
                "url": "http://static01.nyt.com/images/2015/07/04/world/04Greece1-web/04Greece1-web-thumbStandard.jpg",
                "format": "Standard Thumbnail",
                "height": 75,
                "width": 75,
                "type": "image",
                "subtype": "photo",
                "caption": "A Greek Orthodox priest giving money to a man on a street in Thessaloniki, Greece, on Friday.",
                "copyright": "Giannis Papanikos/Associated Press"
            },
            {
                "url": "http://static01.nyt.com/images/2015/07/04/world/04Greece1-web/04Greece1-web-thumbLarge.jpg",
                "format": "thumbLarge",
                "height": 150,
                "width": 150,
                "type": "image",
                "subtype": "photo",
                "caption": "A Greek Orthodox priest giving money to a man on a street in Thessaloniki, Greece, on Friday.",
                "copyright": "Giannis Papanikos/Associated Press"
            },
            {
                "url": "http://static01.nyt.com/images/2015/07/04/world/04Greece1-web/04Greece1-web-articleInline.jpg",
                "format": "Normal",
                "height": 127,
                "width": 190,
                "type": "image",
                "subtype": "photo",
                "caption": "A Greek Orthodox priest giving money to a man on a street in Thessaloniki, Greece, on Friday.",
                "copyright": "Giannis Papanikos/Associated Press"
            },
            {
                "url": "http://static01.nyt.com/images/2015/07/04/world/04Greece1-web/04Greece1-web-mediumThreeByTwo210.jpg",
                "format": "mediumThreeByTwo210",
                "height": 140,
                "width": 210,
                "type": "image",
                "subtype": "photo",
                "caption": "A Greek Orthodox priest giving money to a man on a street in Thessaloniki, Greece, on Friday.",
                "copyright": "Giannis Papanikos/Associated Press"
            }
        ]

【问题讨论】:

  • 可能调用失败?
  • 哦,是的,我忘了在 onFailure 中包含日志语句,更新问题。
  • 不知道为什么有人对此投了反对票,这是一个合理的问题。

标签: java json gson retrofit


【解决方案1】:

好的,我可以通过创建一个扩展 GsonJsonDeserializer&lt;T&gt; 类的自定义反序列化类来完成这项工作。以下代码对我有用:

public class ResultsDeserializerJson implements JsonDeserializer<Result> {

@Override
public Result deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

    JsonElement titleElement = json.getAsJsonObject().get("title");
    JsonElement multimediaElement = json.getAsJsonObject().get("multimedia");
    if (multimediaElement.isJsonArray()) {
        return new Result(
                titleElement.toString(),
                (Multimedia[]) context.deserialize(multimediaElement.getAsJsonArray(), Multimedia[].class));
    } else if (multimediaElement.getAsString().equals("")) {
        Multimedia multimedia = new Multimedia();
        multimedia.setFormat("");
        multimedia.setUrl("");
        return new Result(titleElement.toString(), multimedia);
    } else {
        Log.d("ResultsDeserializerJson", multimediaElement.toString());
        throw new JsonParseException("Unsupported type of multimedia element");
    }
}
}

我将以下构造函数添加到Result.java

public Result(String title, Multimedia ... multimedia) {
    this.mTitle = title.replace("\"", "");;
    mMultimedia = Arrays.asList(multimedia);
}

我仍然觉得这有点 hacky,并且有更好的解决方案。我会对此进行更多调查,但现在这工作正常。您可以向 Multimedia 构造函数添加更多参数,但这在某些方面仍然不能完全满足我的要求。

这是我现在看到的结果:

应用程序的源代码在这里:NYTimes Android App Repo

【讨论】:

    【解决方案2】:

    你的 POJO 不正确,Multimedia 不是一个列表,它只是一个字符串,根据你的 JSON

    【讨论】:

    • 如果您阅读“多媒体”以数组或字符串形式返回的问题,则错误。
    • 嗯,我写的站,阅读错误。它期望在 json 中读取一个数组,但它得到一个字符串
    • 是的,这很明显,我现在正在写一个解决方案。
    猜你喜欢
    • 2015-11-04
    • 2012-02-02
    • 2021-06-17
    • 2017-05-13
    • 1970-01-01
    • 2016-08-16
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多