我得到了这样的JSON响应:
{
"USA": [
"New York",
"Texas",
"Hawaii"
],
"Turkey": [
"Ankara",
"Istanbul"
],
"Lebanon": [
"Beirut",
"Zahle"
]
}
我希望将其作为
public class Country {
private String name = null;
private List<String> cities = null;
}
如果JSON对象没有像
这样的名称,我们如何解析它们{
"name": "USA",
"cities": [
"New York",
.... etc
}
?提前谢谢。
答案 0 :(得分:4)
看起来像是我的地图。尝试将其解析为Map<String, List<String>>
。然后,您可以单独访问键和值。
答案 1 :(得分:1)
Gson的默认DTO字段注释用于简单案例。对于更复杂的反序列化,您可能希望使用自定义类型适配器和(反)序列化器,以避免使用更加Gson惯用方式的弱类型DTO,如地图和列表。
假设您有以下DTO:
final class Country {
private final String name;
private final List<String> cities;
Country(final String name, final List<String> cities) {
this.name = name;
this.cities = cities;
}
String getName() {
return name;
}
List<String> getCities() {
return cities;
}
}
假设&#34;非标准&#34;在JSON布局中,以下反序列化器将递归遍历JSON对象树,以便收集目标国家/地区列表。说,
final class CountriesJsonDeserializer
implements JsonDeserializer<List<Country>> {
private static final JsonDeserializer<List<Country>> countryArrayJsonDeserializer = new CountriesJsonDeserializer();
private static final Type listOfStringType = new TypeToken<List<String>>() {
}.getType();
private CountriesJsonDeserializer() {
}
static JsonDeserializer<List<Country>> getCountryArrayJsonDeserializer() {
return countryArrayJsonDeserializer;
}
@Override
public List<Country> deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
final List<Country> countries = new ArrayList<>();
final JsonObject root = json.getAsJsonObject();
for ( final Entry<String, JsonElement> e : root.entrySet() ) {
final String name = e.getKey();
final List<String> cities = context.deserialize(e.getValue(), listOfStringType);
countries.add(new Country(name, cities));
}
return countries;
}
}
上面的反序列化器将绑定到List<Country>
映射。作为第一步,它&#34;演员&#34;摘要JsonElement
到JsonObject
以遍历其属性("USA"
,"Turkey"
和"Lebanon"
)。假设属性名称本身就是国家名称,城市名称列表(有效的属性值)可以更深入地委托给序列化上下文并解析为List<String>
实例(注意类型标记)。解析name
和cities
后,您可以构建Country
实例并收集结果列表。
如何使用:
private static final Type listOfCountryType = new TypeToken<List<Country>>() {
}.getType();
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(listOfCountryType, getCountryArrayJsonDeserializer())
.create();
public static void main(final String... args) {
final List<Country> countries = gson.fromJson(JSON, listOfCountryType);
for ( final Country country : countries ) {
out.print(country.getName());
out.print(" => ");
out.println(country.getCities());
}
}
已知类型标记和Gson实例是线程安全的,因此它们可以安全地存储为最终静态实例。请注意List<Country>
的自定义类型和CountriesJsonDeserializer
的自定义反序列化程序相互绑定的方式。一旦反序列化完成,它将输出:
USA =&gt; [纽约,德克萨斯州,夏威夷]
土耳其=&gt; [安卡拉,伊斯坦布尔]
黎巴嫩=&gt; [贝鲁特,扎赫尔]
由于我从未使用过Retrofit,因此我使用以下配置尝试了以下代码:
com.google.code.gson:gson:2.8.0
com.squareup.retrofit2:retrofit:2.1.0
com.squareup.retrofit2:converter-gson:2.1.0
定义&#34; geo&#34;服务接口:
interface IGeoService {
@GET("/countries")
Call<List<Country>> getCountries();
}
使用自定义Gson感知转换器构建Retrofit
实例:
// The statics are just borrowed from the example above
public static void main(final String... args) {
// Build the Retrofit instance
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(... your URL goes here...)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
// Proxify the geo service by Retrofit
final IGeoService geoService = retrofit.create(IGeoService.class);
// Make a call to the remote service
final Call<List<Country>> countriesCall = geoService.getCountries();
countriesCall.enqueue(new Callback<List<Country>>() {
@Override
public void onResponse(final Call<List<Country>> call, final Response<List<Country>> response) {
dumpCountries("From a remote JSON:", response.body());
}
@Override
public void onFailure(final Call<List<Country>> call, final Throwable throwable) {
throw new RuntimeException(throwable);
}
});
// Or just take a pre-defined string
dumpCountries("From a ready-to-use JSON:", gson.<List<Country>>fromJson(JSON, listOfCountryType));
}
private static void dumpCountries(final String name, final Iterable<Country> countries) {
out.println(name);
for ( final Country country : countries ) {
out.print(country.getName());
out.print(" => ");
out.println(country.getCities());
}
out.println();
}
如果由于Country
类及其JSON反序列化器而导致类型冲突(我的意思是,您已经有另一个&#34; country&#34;类用于不同目的),只需重命名这个 Country
课程,以免影响&#34;良好的工作&#34;映射。
输出:
从即用型JSON:
USA =&gt; [纽约,德克萨斯州,夏威夷]
土耳其=&gt; [安卡拉,伊斯坦布尔]
黎巴嫩=&gt; [贝鲁特,扎赫尔]来自远程JSON:
USA =&gt; [纽约,德克萨斯州,夏威夷]
土耳其=&gt; [安卡拉,伊斯坦布尔]
黎巴嫩=&gt; [贝鲁特,扎赫尔]