在使用gson解析JSON时如何设置超类属性

时间:2017-04-06 06:48:00

标签: java android gson retrofit

如何在解析JSON数组时设置超类“LookUp”属性id,name 国家:

[ {"ID":5, "CountryNameEN":"UK" }, {"ID":6, "CountryNameEN":"USA" }  ]

例如,当我使用Retrofit 2&amp ;;调用get_lookups_countries()API时用google Gson Library解析响应,我想设置超类实例成员id&a​​mp;具有相同的派生类“国家”值的名称

 @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;
}

1 个答案:

答案 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来实现复杂(反)序列化策略。