改造+ gson反序列化器:返回数组中
我有api返回json:
{"countries":[{"id":1,"name":"Australia"},{"id":2,"name":"Austria"}, ... ]}
我写模特班(Kotlin lang)
data class Country(val id: Int, val name: String)
我想要使用retorift返回List <Models.Country>,从json中的“countries”字段请求
我下面写:
interface DictService { @GET("/json/countries") public fun countries(): Observable<List<Models.Country>> companion object { fun create() : DictService { val gsonBuilder = GsonBuilder() val listType = object : TypeToken<List<Models.Country>>(){}.type gsonBuilder.registerTypeAdapter(listType, CountriesDeserializer) gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) val service = Retrofit.Builder() .baseUrl("...") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gsonBuilder.create())) .build() return service.create(DictService::class.java) } } object CountriesDeserializer : JsonDeserializer<List<Models.Country>> { override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): List<Models.Country>? { val res = ArrayList<Models.Country>() if(json!=null) { val countries = json.asJsonObject.get("countries") if (countries.isJsonArray()) { for (elem: JsonElement in countries.asJsonArray) { res.add(Gson().fromJson(elem, Models.Country::class.java)) } } } return null; } } }
但是我得到的错误:java.lang.IllegalStateException:期望BEGIN_ARRAY,但BEGIN_OBJECT行1列2路径$ CountriesDeserializer代码不要执行,甚至! 他们想从我那里得到什么?
也许我需要写我自己的TypeAdapterFactory?
我不想使用模型类
class Countries { public List<Country> countries; }
如果你的意图是简化接口并隐藏中间包装对象,我想最简单的方法就是向DictService
添加一个扩展方法, DictService
所示:
interface DictService { @GET("/json/countries") fun _countries(): Observable<Countries> } fun DictService.countries() = _countries().map { it.countries } data class Countries(val countries: List<Country> = listOf())
然后可以如下使用:
val countries:Observable<List<Country>> = dictService.countries()
我找到了方法:
object CountriesTypeFactory : TypeAdapterFactory { override fun <T : Any?> create(gson: Gson?, type: TypeToken<T>?): TypeAdapter<T>? { val delegate = gson?.getDelegateAdapter(this, type) val elementAdapter = gson?.getAdapter(JsonElement::class.java) return object : TypeAdapter<T>() { @Throws(IOException::class) override fun write(outjs: JsonWriter, value: T) { delegate?.write(outjs, value) } @Throws(IOException::class) override fun read(injs: JsonReader): T { var jsonElement = elementAdapter!!.read(injs) if (jsonElement.isJsonObject) { val jsonObject = jsonElement.asJsonObject if (jsonObject.has("countries") && jsonObject.get("countries").isJsonArray) { jsonElement = jsonObject.get("countries") } } return delegate!!.fromJsonTree(jsonElement) } }.nullSafe() } }
但是,我认为,这样的问题是非常复杂的决定。 还有另一种更简单的方法吗?
另一个:我发现我的初始代码从开始meassage中的错误! 它工作正常,如果替换ListList ArrayList!
我会用杰克逊来完成这个任务。 试试这个https://github.com/FasterXML/jackson-module-kotlin
val mapper = jacksonObjectMapper() data class Country(val id: Int, val name: String) // USAGE: val country = mapper.readValue<Country>(jsonString)