我有一个外部 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 放在那里。
你的解串器看起来像:
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/