android - Retrofit - 解析没有 SerializedName 的 json

标签 android api gson retrofit

我有一个外部 Web 服务,它返回未命名的 json,如下所示;

[
  {
    "page": 1,
    "pages": 1,
    "per_page": "310",
    "total": 304
  },
  [
    {
      "id": "ABW",
      "iso2Code": "AW",
      "name": "Aruba",
      "region": {
        "id": "LCN",
        "iso2code": "ZJ",
        "value": "Latin America & Caribbean "
      },
      "adminregion": {
        "id": "",
        "iso2code": "",
        "value": ""
      },
      "incomeLevel": {
        "id": "HIC",
        "iso2code": "XD",
        "value": "High income"
      },
      "lendingType": {
        "id": "LNX",
        "iso2code": "XX",
        "value": "Not classified"
      },
      "capitalCity": "Oranjestad",
      "longitude": "-70.0167",
      "latitude": "12.5167"
    },
    {
      "id": "AFG",
      "iso2Code": "AF",
      "name": "Afghanistan",
      "region": {
        "id": "SAS",
        "iso2code": "8S",
        "value": "South Asia"
      },
      "adminregion": {
        "id": "SAS",
        "iso2code": "8S",
        "value": "South Asia"
      },
      "incomeLevel": {
        "id": "LIC",
        "iso2code": "XM",
        "value": "Low income"
      },
      "lendingType": {
        "id": "IDX",
        "iso2code": "XI",
        "value": "IDA"
      },
      "capitalCity": "Kabul",
      "longitude": "69.1761",
      "latitude": "34.5228"
    }
  ]
]

我有CountriesResponse类:

public class CountriesResponse {
    private ResponseDetails responseDetails;
    private List<Country> countries;

响应详细信息:

class ResponseDetails {
    @SerializedName("page")
    @Expose
    private int page;
    @SerializedName("pages")
    @Expose
    private int pages;
    @SerializedName("per_page")
    @Expose
    private String perPage;
    @SerializedName("total")
    @Expose
    private int total;

国家:

public class Country {
    @SerializedName("name")
    private String name;

    @SerializedName("capitalCity")
    private String capital;

ApiInterface

public interface ApiInterface {
//http://api.worldbank.org/v2/countries/all?per_page=310&format=json
    @GET("countries/all")
    Call<ArrayList<Country>> getCountries(@Query("per_page") int per_page, @Query("format") String format);
}

CountriesResponse 类中,我假设我要使用 @SerializedName 注释属性。我如何解析 json 看到 json 中的对象和数组没有名称。

最佳答案

1) 您的调用返回了错误的类型。它应该返回顶级对象 CountriesResponse您持有 ResponseDetails因为你想取回所有 json,以便解析出匿名元素。

2) 在 CountriesResponse你有一个List<Country>.序列化注释不能在 Country 中使用因为那里没有匹配的名字。这必须手动反序列化。所以摆脱@SerializedName这两个字段都位于“国家/地区”。

3) 使用 Gson 添加自定义反序列化器,请参见此处:Retrofit: how to parse a JSON array that combines an array and an object?

您需要将顶级 JSON 元素解析为反序列化代码中包含 2 个元素的数组:

    final JsonArray jsonArray = json.getAsJsonArray();
    JsonObject rd = jsonArray get(0); //this is the ResponseDetails object
    CountriesResponse cr = new CountriesResponse();
    cr.setResponseDetails(rd);
    JsonArray countries = jsonArray.get(1) //<-- this is your List<Country>
    //now you must iterate list `countries`and create a new Country for each one then add it to the List<Country> in CountriesResponse

要清楚地看到结构,您可以使用 https://jsoneditoronline.org并将您的 JSON 放在那里。 your JSON

你的解串器看起来像:

public class MyDeserializer
    implements JsonDeserializer<CountriesResponse> {
  @Override
  public CountriesResponse deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
      throws JsonParseException {
        final JsonArray jsonArray = json.getAsJsonArray();
        JsonObject rdObject =jsonArray get(0); //this is the ResponseDetails object
        CountriesResponse cr = new CountriesResponse();
        ///you might get this part for free with Retrofit since it is the top level object and JSON is expected as array of obj by default
        ////but if you did it manually it would look like:
        ResponseDetails rd = new ResponseDetails();
        //... now iterate the rdObject , setting the fields
         ...
        cr.setResponseDetails(rd);

        List cList = new ArrayList();
        JsonArray arr = jsonArray.get(1); //<-- this is your List<Country>
        //now you must iterate list and create a new Country for each one then add it to the List<Country> and set it on your CountriesResponse
        for (int i = 0; i < arr.length(); i++) {
           JSONObject jo = arr.getJSONObject(i);
           Country c = new Country();
           c.setName(jo.get("name");
           ...  set the capitalCity the same way
           cList.add();
        }
        cr.setCountriesList(cList)

       ...  
       return cr;
}

现在您可以使用 cr.getCountriesList() 来显示您的数据。 JSONElements 可能需要转换,但这本质上就是要做的事情。 Retrofit/POJO/JSON 转换器不提供的一件事是匿名元素支持。

如果您需要将列表保留在 Room 中,您还需要一个 TypeConverter。

关于android - Retrofit - 解析没有 SerializedName 的 json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51958560/

相关文章:

java - AWS API Gateway 和 Lambda 返回图像

java - 如何禁用 gson 中的字符编码?

android - 如何从文本框android存储值?

android - MonoDroid 进度对话框

api - 我应该针对哪个版本的 OpenGL/Direct3D 以获得最佳兼容性?

css - HTTParty 类中未定义的方法

java - 如何用接口(interface)序列化一个类?

java - 使用 GSON 在 Java 中打开 .txt 文件

android - Context.startForegroundService() 然后没有调用 Service.startForeground() 即使我停止了服务

android 在 Eclipse 图形布局中添加设备