当前与PolymorphicJsonAdapterFactory和Kotlins密封类有关。我有一个可返回多态家庭组件的API,我正在尝试使用Kotlin中的Moshi解析并创建多态对象,但出现以下错误:
Caused by: java.lang.IllegalArgumentException: Cannot serialize abstract class home.HomeComponent
for class home.HomeComponent
for java.util.List<home.HomeComponent> components
for class home.HomeContent
代码:
sealed class HomeComponent(@Json(name = "_type") val type: HomeContentType) {
data class BannerComponent(@field:Json(name = "_id")
val id: String,
val image: String) : HomeComponent(HomeContentType.banner)
data class SpecialProductsComponent(@field:Json(name = "_id")
val id: String,
val style: List<Product>) : HomeComponent(HomeContentType.specialProducts)
data class CarouselBannerComponent(@field:Json(name = "_id")
val id: String,
val style: String,
val images: List<String>) : HomeComponent(HomeContentType.carousel)
}
enum class HomeContentType {
@Json(name = "banner")banner,
@Json(name = "products")Products,
@Json(name = "carousel")carousel
}
ApiFetcher类:
class HomeApiFetcher(private val backend: HomeContentBackend) : HomeFetcher {
companion object {
fun from(retrofit: Retrofit,
moshi: Moshi): HomeApiFetcher {
val moshi = moshi.newBuilder()
.add(
PolymorphicJsonAdapterFactory.of(HomeComponent::class.java, "_type")
.withSubtype(HomeComponent.BannerComponent::class.java, HomeContentType.banner.name)
.withSubtype(HomeComponent.SpecialProductsComponent::class.java, HomeContentType.specialProducts.name)
.withSubtype(HomeComponent.CarouselBannerComponent::class.java, HomeContentType.carousel.name))
.add(KotlinJsonAdapterFactory())
.build()
val homeBackend = retrofit
.newBuilder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
.create(HomeContentBackend::class.java)
return HomeApiFetcher(homeBackend)
}
}
override fun getHomeContent(): Single<HomeContent> {
return backend.load()
}
}
来自API的JSON:
{
"common": {
"background": "",
"backgroundType": "NONE",
"floatingImgs": {
"left": "",
"right": ""
},
"actualDate": "2019-09-23T15:03:20.8626882Z"
},
"components": [{
"image": "http://image1.url",
"_id": "carousel1",
"style": "SLIDE",
"_type": "banner"
},
{
"products": [],
"_id": "id1",
"style": "CARD",
"_type": "products"
},
{
"images": ["http://image1.url",
"http://image1.url",
"http://image1.url"
],
"_id": "carousel1",
"style": "SLIDE",
"_type": "carousel"
}
]
}
我不确定我的代码有什么问题。我收到Cannot serialize abstract class HomeComponent
错误
答案 0 :(得分:2)
我已将@field:Json
更改为Json
,将Products
更改为products
和SpecialProductsComponent
字段。所以最后我得到了:
sealed class HomeComponent(@Json(name = "_type") val type: HomeContentType) {
data class BannerComponent(
@Json(name = "_id")
val id: String,
val image: String
) : HomeComponent(HomeContentType.banner)
data class SpecialProductsComponent(
@Json(name = "_id")
val id: String,
val style: String,
val products: List<Product>
) : HomeComponent(HomeContentType.products)
data class CarouselBannerComponent(
@Json(name = "_id")
val id: String,
val style: String,
val images: List<String>
) : HomeComponent(HomeContentType.carousel)
}
enum class HomeContentType {
@Json(name = "banner")
banner,
@Json(name = "products")
products,
@Json(name = "carousel")
carousel
}
,现在看来一切正常。我用以下代码检查了它:
fun main() {
val moshi = Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(HomeComponent::class.java, "_type")
.withSubtype(HomeComponent.BannerComponent::class.java, HomeContentType.banner.name)
.withSubtype(HomeComponent.SpecialProductsComponent::class.java, HomeContentType.products.name)
.withSubtype(HomeComponent.CarouselBannerComponent::class.java, HomeContentType.carousel.name)
)
.add(KotlinJsonAdapterFactory())
.build()
val json = """
[
{
"image": "http://image1.url",
"_id": "carousel1",
"style": "SLIDE",
"_type": "banner"
},
{
"products": [],
"_id": "id1",
"style": "CARD",
"_type": "products"
},
{
"images": [
"http://image1.url",
"http://image1.url",
"http://image1.url"
],
"_id": "carousel1",
"style": "SLIDE",
"_type": "carousel"
}
]
""".trimIndent()
val adapter =
moshi.adapter<List<HomeComponent>>(Types.newParameterizedType(List::class.java, HomeComponent::class.java))
val result = adapter.fromJson(json)
println(result)
}