如何在解析JSON数组时设置超类“LookUp”属性id,name 国家:
[ {"ID":5, "CountryNameEN":"UK" }, {"ID":6, "CountryNameEN":"USA" } ]
例如,当我使用Retrofit 2&amp ;;调用get_lookups_countries()API时用google Gson Library解析响应,我想设置超类实例成员id&具有相同的派生类“国家”值的名称
@GET(Constants.LookUps.GET_COUNTRIES) Call<List<Country>> get_lookups_countries();
Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(LookUp.class,new LookupsDeserializer())
.create();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient.build())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
return retrofit.create(APIEndpointVatTax.class);
public class LookUp {
int id;
String name;
}
public class Country extends LookUp {
@SerializedName("ID")
@Expose
private Integer iD;
@SerializedName("CountryNameEN")
@Expose
private String countryNameEN;
}
答案 0 :(得分:1)
您的JSON映射似乎有些问题:您正在尝试将超类字段绑定到子类字段,但这是一个接口可能是更好的选择,因为您的意图只是< em>询问反序列化对象的id和名称。
我会这样做:
interface LookUp {
int getId();
String getName();
}
final class CountryByInterface
implements LookUp {
@SerializedName("ID")
private final Integer id = null;
@SerializedName("CountryNameEN")
private final String name = null;
@Override
public int getId() {
return id;
}
@Override
public String getName() {
return name;
}
}
因此它可以很容易地使用(Java 8仅用于演示目的):
final Gson gson = new Gson();
final Type countryListType = new TypeToken<List<CountryByInterface>>() {
}.getType();
try ( final Reader reader = getPackageResourceReader(Q43247712.class, "countries.json") ) {
gson.<List<CountryByInterface>>fromJson(reader, countryListType)
.stream()
.map(c -> c.getId() + "=>" + c.getName())
.forEach(System.out::println);
}
如果由于某种合理的理由你真的需要超类来保存这些字段,你必须实现一个后处理器(受PostConstructAdapterFactory启发)。说,
abstract class AbstractLookUp {
int id;
String name;
abstract int getId();
abstract String getName();
final void postSetUp() {
id = getId();
name = getName();
}
}
final class CountryByClass
extends AbstractLookUp {
@SerializedName("ID")
private final Integer id = null;
@SerializedName("CountryNameEN")
private final String name = null;
@Override
int getId() {
return id;
}
@Override
String getName() {
return name;
}
}
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Check if it's a class we can handle: AbstractLookUp
if ( AbstractLookUp.class.isAssignableFrom(typeToken.getRawType()) ) {
// Get the downstream parser for the given type
final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
return new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegateTypeAdapter.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
// Deserialize it as an AbstractLookUp instance
final AbstractLookUp abstractLookUp = (AbstractLookUp) delegateTypeAdapter.read(in);
// And set it up
abstractLookUp.postSetUp();
@SuppressWarnings("unchecked")
final T result = (T) abstractLookUp;
return result;
}
};
}
return null;
}
})
.create();
final Type countryListType = new TypeToken<List<CountryByClass>>() {
}.getType();
try ( final Reader reader = getPackageResourceReader(Q43247712.class, "countries.json") ) {
gson.<List<CountryByClass>>fromJson(reader, countryListType)
.stream()
.map(c -> ((AbstractLookUp) c).id + "=>" + ((AbstractLookUp) c).name)
.forEach(System.out::println);
}
两个例子都产生
5 =&GT; UK
6 =&gt;美国
然而,我发现第一种方法设计得更好,更容易使用,而第二种方法则演示了如何配置Gson来实现复杂(反)序列化策略。