简体   繁体   English

Kotlin 反射

[英]Kotlin reflection

With Retrofit , I am fetching data and getting JSONObject with the structure like this for example:使用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
        }
    ]
}

Now, when I get this response, I need to make a parser that will actually take the type from every tile and match it with the class that already exists inside application.现在,当我收到此响应时,我需要创建一个解析器,它实际上会从每个图块中获取类型,并将其与应用程序中已经存在的类匹配。 I need to basically from this response to create new one with token and tiles list but in this case tiles will reflect to actual class in app.我基本上需要从这个响应中创建一个带有令牌和图块列表的新响应,但在这种情况下,图块将反映到应用程序中的实际类。

Any idea what is proper way to do it?!知道什么是正确的方法吗?

I don't know what your classes look like, but suppose it's this for example:我不知道您的课程是什么样的,但假设是这样的:

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

Then you could make this as response object然后你可以把它作为响应对象

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
    }
}

And then you can call toTile() on the individual TileResponse objects or get the full list by doing getTilesObjects() on the response object然后您可以在各个TileResponse对象上调用toTile()或通过对响应对象执行getTilesObjects()来获取完整列表

Because you mention Reflection in your question's title:因为您在问题的标题中提到了反射:

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())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM