Android,Kotlin:从反射

时间:2018-04-23 15:07:56

标签: android firebase reflection kotlin deserialization

所以我编写了一个将Firebase快照反序列化为类的类。我这样做的原因是因为我从Firebase获取了一个String对象,我实际上想要实例化一个不同的类。 getValue不支持这个,所以我必须为它做一个解决方法。

现在一切正常,除了地图部分。 DataSnapshot确实想要GenericTypeIndicator作为参数,但由于一切都将动态完成,我不知道如何用反射来做到这一点。

这是我目前的代码:

fun <T> deserialize(dataSnapshot: DataSnapshot, clazz: Class<T>): T {
    val obj = clazz.newInstance()

    dataSnapshot.children.forEach {
        val field = try {
            clazz.getDeclaredField(it.key)
        } catch(e: NoSuchFieldException) { return@forEach }

        field.isAccessible = true

        when(field.type){
            Translation::class.java ->
                field.set(obj, Translation(it.getValue(String::class.java)!!))
            Map::class.java -> { /* Here we need to do crazy Map GenericTypeIndicator stuff */ }
            else -> field.set(obj, it.getValue(field.type))
        }
    }

    return obj
}


我删除Map案例时遇到的错误是:

Class java.util.Map has generic type parameters, please use GenericTypeIndicator instead


如果我实际上使用GenericTypeIndicator与HashMap,它将给我以下错误:

com.google.firebase.database.DatabaseException: Not a direct subclass of GenericTypeIndicator: class java.lang.Object

不是我想这样做,因为这必须最终动态完成。

现在我很茫然,所以任何帮助都会受到赞赏,主要是因为每个对象的地图不同所以我不能只有预定义的通用。

1 个答案:

答案 0 :(得分:0)

我通过执行isAssignableFrom检测Map变量,并为GenericTypeIndicator创建一个对象。

所以唯一需要改变的是代码中的when部分:

when {
    field.type == Translation::class.java ->
        field.set(obj, Translation(it.getValue(String::class.java)!!))
    Map::class.java.isAssignableFrom(field.type) ->
        field.set(obj, it.getValue(object: GenericTypeIndicator<HashMap<String, Any>>(){}))
    else -> field.set(obj, it.getValue(field.type))
}

Firebase只接受String作为键,因此我们可以将其固定,但它不喜欢使用*表示法来表示值,但我们可以将它设为Any,它似乎工作正常。 / p>

我希望这可以帮助其他可能遇到过这个问题的人x)