Интерфейс фабрики Kotlin с дженериками

У меня есть заводский интерфейс в моем коде Kotlin, например (используя Guava TypeToken ):

 interface ResultMapperFactory { fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? } 

Все идет нормально. Это очень легко использовать при вызове, однако для реализации почти всегда требуется небезопасное исполнение:

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

Это уродливо, но я победил его с помощью трюка. Во-первых, небольшая функция полезности для создания экземпляров TypeToken :

 inline fun <reified T> typeToken(): TypeToken<T> = object : TypeToken<T>() {} 

Теперь я добавил объект-компаньон к моему заводскому интерфейсу:

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

Это позволяет мне иметь непроверенный (но безопасный) перевод в одном месте, и я могу написать код следующим образом:

 val stringMapper: ResultMapper<String> = TODO() val stringMapperFactory = ResultMapperFactory<String> { type, context -> stringMapper } 

Однако этот подход также разваливается, как только я хочу реализовать фабрику, которая принимает TypeToken<List<T>> и возвращает ResultMapper<List<T>> , потому что мне негде поставить этот параметр T

Я очень хочу услышать ваши предложения.

Я нашел решение самостоятельно, используя invoke оператора, которую я опубликовал в своем первоначальном вопросе, могу написать следующее:

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