我在反序列化方面遇到问题。我有来自服务器的 json
{
"rooms": [
{
"id": 1,
"name": "Стандартный номер с видом на бассейн",
"price": 186600,
"price_per": "За 7 ночей с перелетом",
"peculiarities": [
"Включен только завтрак",
"Кондиционер"
],
"image_urls": [
"https://www.atorus.ru/sites/default/files/upload/image/News/56871/%D1%80%D0%B8%D0%BA%D1%81%D0%BE%D1%81%20%D1%81%D0%B8%D0%B3%D0%B5%D0%B9%D1%82.jpg",
"https://q.bstatic.com/xdata/images/hotel/max1024x768/267647265.jpg?k=c8233ff42c39f9bac99e703900a866dfbad8bcdd6740ba4e594659564e67f191&o=",
"https://worlds-trip.ru/wp-content/uploads/2022/10/white-hills-resort-5.jpeg"
]
},
{
"id": 2,
"name": "Люкс номер с видом на море",
"price": 289400,
"price_per": "За 7 ночей с перелетом",
"peculiarities": [
"Все включено",
"Кондиционер",
"Собственный бассейн"
],
"image_urls": [
"https://mmf5angy.twic.pics/ahstatic/www.ahstatic.com/photos/b1j0_roskdc_00_p_1024x768.jpg?ritok=65&twic=v1/cover=800x600",
"https://www.google.com/search?q=%D0%BD%D0%BE%D0%BC%D0%B5%D1%80+%D0%BB%D1%8E%D0%BA%D1%81+%D0%B2+%D0%BE%D1%82%D0%B5%D0%BB%D0%B8+%D0%B5%D0%B3%D0%B8%D0%BF%D1%82%D0%B0+%D1%81+%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%BC+%D0%B1%D0%B0%D1%81%D1%81%D0%B5%D0%B9%D0%BD%D0%BE%D0%BC&tbm=isch&ved=2ahUKEwilufKp-4KBAxUfJxAIHR4uAToQ2-cCegQIABAA&oq=%D0%BD%D0%BE%D0%BC%D0%B5%D1%80+%D0%BB%D1%8E%D0%BA%D1%81+%D0%B2+%D0%BE%D1%82%D0%B5%D0%BB%D0%B8+%D0%B5%D0%B3%D0%B8%D0%BF%D1%82%D0%B0+%D1%81+%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%BC+%D0%B1%D0%B0%D1%81%D1%81%D0%B5%D0%B9%D0%BD%D0%BE%D0%BC&gs_lcp=CgNpbWcQAzoECCMQJ1CqAVi6HGDmHWgAcAB4AIABXIgB3wySAQIyNZgBAKABAaoBC2d3cy13aXotaW1nwAEB&sclient=img&ei=Y3fuZOX7KJ_OwPAPntyE0AM&bih=815&biw=1440#imgrc=Nr2wzh3vuY4jEM&imgdii=zTCXWbFgrQ5HBM",
"https://tour-find.ru/thumb/2/bsb2EIEFA8nm22MvHqMLlw/r/d/screenshot_3_94.png"
]
}
]
}
我想要一份清单
HotelApi.kt
@GET("f9a38183-6f95-43aa-853a-9c83cbb05ecd")
suspend fun getRooms(): Response<List<Room>>
为此我写了一个 JsonDeserializer
RoomListDeserializer.kt
class RoomListDeserializer : JsonDeserializer<List<Room>> {
override fun deserialize(
json: JsonElement,
typeOfT: Type?,
context: JsonDeserializationContext?
): List<Room> {
val roomList = mutableListOf<Room>()
val roomsJsonArray = json.asJsonObject.getAsJsonArray("rooms")
Log.d("TAG", "deserialize: ${roomsJsonArray}")
roomsJsonArray?.forEach { roomJson ->
val room = context?.deserialize<Room>(roomJson, Room::class.java)
room?.let { roomList.add(it) }
}
return roomList
}
}
(日志没有呼出) 我将它添加到 GsonBuilder
AppModule.kt
@Provides
@Singleton
fun provideGsonConverter(): Gson = GsonBuilder()
.registerTypeAdapter(object : TypeToken<List<Room>>(){}.type, RoomListDeserializer())
.create()
@Provides
@Singleton
fun provideHotelApi(
client: OkHttpClient,
gson: Gson
): HotelsApi = Retrofit.Builder()
.baseUrl(HotelsApi.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(HotelsApi::class.java)
它不起作用
HotelRepositoryImpl.kt
override suspend fun getRooms(): Flow<Resource<List<Room>>> = flow {
try {
val response = api.getRooms()
if (response.body() != null) {
emit(Resource.Success(response.body()!!))
} else {
emit(Resource.Error(context.getString(R.string.response_is_null)))
}
} catch (e: Exception) {
Log.d("TAG", "getRooms: $e")
emit(handleException(e, context))
}
}.flowOn(Dispatchers.IO)
期望是
getRooms: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
但如果我创建一个带有房间列表字段的类,一切都会正常工作
data class Test(
val rooms: List<Room>
)
我的房间实体
data class Room(
val id: Int,
@SerializedName("image_urls")
val imageUrls: List<String>,
val name: String,
val peculiarities: List<String>,
val price: Int,
@SerializedName("price_per")
val pricePer: String
)
我能实现我的目标吗?如何实现?
您为
GsonBuilder.registerTypeAdapter
提供的类型已被准确检查。尽管文档可能还不够清楚。当您为 List<Room>
注册适配器时,您只需为该确切类型注册它。它既不会用于 ArrayList<Room>
也不会用于 List<? extends Room>
或类似用途。
这似乎是您的代码无法正常工作的部分原因。看起来 Kotlin 表达式
object : TypeToken<List<Room>>(){}.type
实际上创建了一个 List<? extends Room>
(调试时可以看到)。所以你的自定义解串器将不会被调用。
也许您可以通过将
object : TypeToken<List<Room>>(){}.type
替换为 TypeToken.getParameterized(List::class.java, Room::class.java).type
来解决此问题,但这似乎相当脆弱。TypeAdapterFactory
来实现自定义反序列化逻辑,但随后您必须手动检查类型是否为 List<Room>
或子类型。
因此,也许最简单、最可靠的解决方案实际上是拥有一些具有
rooms
属性的封闭类型,就像您使用 Test
数据类所做的那样。