Kotlin reflection



对于Retrofit,我正在获取数据并使用这样的结构获得JSONObject,例如:

{
"token": "some-token",
"tiles": [
{
"id": "id-1",
"type": "RedTile",
"title": "This red title",
"stuff": "hello world"
},
{
"id": "id-2",
"type": "BlueTile",
"title": "This blue title",
"value": 200
}
]
}

现在,当我得到这个响应时,我需要创建一个解析器,它将实际从每个tile中获取类型,并将其与应用程序中已经存在的类进行匹配。我基本上需要从这个响应创建一个新的令牌和瓷砖列表,但在这种情况下,瓷砖将反映到应用程序中的实际类。

你知道怎么做才合适吗?

我不知道你的类是什么样子的,但假设它是这样的,例如:

sealed interface Tile
data class RedTile(val title: String, val stuff: String) : Tile
data class BlueTile(val title: String, val value: Int) : Tile

然后你可以把它作为响应对象

data class Response (
val token: String,
val tiles: List<TileResponse>
) {
fun getTilesObjects() = tiles.mapNotNull { it.toTile() }
}
data class TileResponse (
val id: String,
val type: String,
val title: String,
val stuff: String? = null,
val value: Int? = null
){
fun toTile() : Tile? {
if (type == "RedTile" && stuff != null) return RedTile(title, stuff)
if (type == "BlueTile" && value != null) return BlueTile(title, value)
return null
}
}

然后你可以在单个TileResponse对象上调用toTile()或通过在响应对象上执行getTilesObjects()来获得完整的列表

因为你在题目中提到了Reflection:

import kotlin.reflect.full.declaredMemberProperties
data class TileResponse(val id: String, val type: String, val title: String, val stuff: String? = null, val value: Int? = null)
data class Response(val token: String, val tiles: List<Tile>)
sealed interface Tile
data class RedTile(val title: String, val stuff: String) : Tile
data class BlueTile(val title: String, val value: Int) : Tile
fun getTiles(): List<Tile> {
return tileResponses
.filter { tileResponse -> mapTypeToClass.containsKey(tileResponse.type) }
.map { tileResponse ->
val clazz = mapTypeToClass[tileResponse.type]!!
val constructor = clazz.constructors.first()
val declaredMemberProperties = tileResponse::class.declaredMemberProperties
val fields = constructor.parameters.map { parameter ->
parameter to declaredMemberProperties.first { it.name == parameter.name }
}
val arguments = fields.associate { (parameter, property) ->
parameter to property.call(tileResponse)
}
constructor.callBy(arguments)
}
}
val tileResponses = listOf(
TileResponse("id-1", "RedTile", "This red title", "hello world", null),
TileResponse("id-2", "BlueTile", "This blue title", "null", 200)
)
val mapTypeToClass = mapOf(
"RedTile" to RedTile::class,
"BlueTile" to BlueTile::class,
)
val response = Response("some-token", getTiles())

最新更新