Итак, я написал класс, который десериализует снимок Firebase в класс. Причина, по которой я это сделал, заключается в том, что я получаю объект String из Firebase, для которого я действительно хочу создать экземпляр другого класса. Это не поддерживается 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
}
Ошибка, которую я получаю при удалении корпуса карты:
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
Не то чтобы я хотел сделать это таким образом, потому что в конечном итоге это должно происходить динамически.
Теперь я в растерянности, поэтому любая помощь будет принята с благодарностью, в основном потому, что карта отличается для каждого объекта, поэтому я не могу просто иметь предопределенный общий.
Я обнаружил, что переменная Map работает, выполнив isAssignableFrom и создав объект для 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, и, похоже, он работает нормально.
Надеюсь, это поможет другим людям, которые могут когда-либо столкнуться с этой проблемой x)