【问题标题】:Define Retrofit return type using interface instead of class使用接口而不是类定义改造返回类型
【发布时间】:2017-01-21 10:22:49
【问题描述】:
有简单的改造界面
interface Movies {
@GET("movies/trending")
fun trending(): Observable<List<TrendingMovie>>
}
是否可以将 TrendingMovie 定义为接口(结果将是实现此接口的匿名类的 Observable 发射列表)?
(我试过这样做,但我得到 java.lang.IllegalArgumentException: No JsonAdapter for interface com.test.TrendingMovie)
【问题讨论】:
标签:
android
kotlin
retrofit2
【解决方案1】:
是的,这绝对是可能的,但需要您为接口添加自定义反序列化器。这是通过为您使用的反序列化工具注册自定义类型反序列化器来完成的。
使用 Jackson(毕竟我建议将其用于处理 Kotlin 类),这是通过将 Module 添加到 ObjectMapper 来完成的。以下是我使用jackson-module-kotlin 执行此操作的步骤:
-
创建自定义Module,并为您的界面添加JsonDeserializer:
fun trendingMovieModule(): Module = SimpleModule().apply {
val deserializer: JsonDeserializer<TrendingMovie> = object : JsonDeserializer<TrendingMovie>() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): TrendingMovie {
val node = p.codec.readTree<JsonNode>(p)
return object : TrendingMovie { // Your anonymous class here, for example:
val name = node["movie"]["title"]
val watchers = node["watchers"].intValue()
override fun toString(): String = "$name, watchers: $watchers"
}
}
}
addDeserializer(TrendingMovie::class.java, deserializer)
}
-
使用您用于Retrofit 构建器的ObjectMapper 注册模块:
val mapper = jacksonObjectMapper()
.registerModule(trendingMovieModule())
-
在Retrofit 构建器中使用mapper:
val r = Retrofit.Builder()
// other necessary configuration omitted, e.g. custom OkHttpClient
.baseUrl("https://api.trakt.tv")
.addConverterFactory(JacksonConverterFactory.create(mapper))
.build().create(Movies::class.java)
JacksonConverterFactory 需要依赖:converter-jackson。
-
完成!它现在应该可以工作了:
r.trending().flatMap { Observable.from(it) }.forEach(::println)
完整的源文件:(here)