Interfaz de fábrica de Kotlin con generics
Tengo una interfaz de fábrica en mi código de Kotlin, como tal (usando TypeToken
de Guava):
interface ResultMapperFactory { fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? }
Hasta aquí todo bien. Esto es muy fácil de usar al llamarlo, sin embargo, la implementación casi siempre requiere un lanzamiento inseguro:
- La image existe, no es nula, pero obtengo una NullPointerException en ella
- Cómo establecer no nulo para params de funciones en kotlin
- cómo search información usando la biblioteca de volley en kotlin
- ¿Mezcla generics de class y function en Kotlin?
- Usando RxJava para get un resultado distinto con Realm y Retrofit
object StringFactory : ResultMapperFactory { override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? { return if (type.rawType == String::class.java) MyStringMapper as ResultMapper<T> else null } }
Esto es feo, pero lo he superado con un buen truco. Primero, una pequeña function de utilidad para crear instancias TypeToken
:
inline fun <reified T> typeToken(): TypeToken<T> = object : TypeToken<T>() {}
Ahora agregué un object complementario a mi interfaz de fábrica:
companion object { inline operator fun <reified R> invoke(crossinline body: (TypeToken<R>, MapperLookupContext) -> ResultMapper<R>?): ResultMapperFactory { val t = typeToken<R>().type return object : ResultMapperFactory { override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? { return if (type.isSubtypeOf(t)) body(type as TypeToken<R>, context) as ResultMapper<T>? else null } } } }
Esto me permite tener el elenco sin marcar (pero seguro) en un solo lugar y puedo escribir código como el siguiente:
val stringMapper: ResultMapper<String> = TODO() val stringMapperFactory = ResultMapperFactory<String> { type, context -> stringMapper }
Sin embargo, este enfoque también se desmorona tan pronto como quiero implementar una fábrica que toma un TypeToken<List<T>>
y devuelve un ResultMapper<List<T>>
, porque no tengo ningún lugar para poner ese parámetro T
Estoy ansioso por escuchar tus sugerencias.
- ¿Cómo configuro un ícono (dibujable) para un button en anko?
- Genéricos de Java en Kotlin: utilice el tipo de raw de Java como parámetro de método en Kotlin
- La variación del sitio de la statement puede causar ClassCastException
- ¿Cómo puedo establecer el JsName para el campo de respaldo de una propiedad en Kotlin?
- ¿Qué hay de diferente entre dos constructores?
- Escriba código html sin procesar dentro de kotlinx.html DSL
- Android Kotlin Extension super calling
- Confusión con los generics de Kotlin
Encontré la solución yo mismo, utilizando la diversión del operador de invoke
que publiqué en mi pregunta original, puedo escribir lo siguiente:
private class ListResultMapper<out E>(private val elementMapper: ResultMapper<E>) : ResultMapper<List<E>> { /* ... */ } val listMapperFactory = ResultMapperFactory<List<*>> { type, context -> context.resultMapperFactory.get(type.elementType(), context)?.let { ListResultMapper(it) } }
- Migración de Groovy gradle a Kotlin gradle (falta extensión o conversión de cierre, no estoy seguro)
- ¿Cómo get el estado de entrega del post usando smack?