从非具体化类型参数实例化 类

Instantiating classes from non-reified type parameters

我正在构建一个 ORM 以在 Kotlin 中与 jasync-sql 一起使用,但有一个我无法解决的基本问题。我认为归结为:

How can one instantiate an instance of a class of type T, given a non-reified type parameter T?

众所周知的 Spring Data project manages this,您可以在其 CrudRepository<T, ID> 接口中看到它,该接口使用类型参数 T 进行参数化,并公开 return 类型实例的方法T。我查看了源代码但没有取得多大成功,但是 某处 它必须能够在运行时实例化 class 类型 T ,尽管事实上T 正在被删除。

当我查看自己的 AbstractRepository<T> 摘要 class 时,我不知道如何获取对 T 构造函数的引用,因为它需要访问 T::class.constructors 这可以理解地失败,除非 T 是具体化的类型。鉴于在内联函数的参数中只能使用具体化的类型,我有点不知道它是如何工作的?

在您自己的 CrudRepository 中,您可以添加一个带有内联乐趣的伴随对象,它负责通过将相应的 class.

传递给它来实例化您的存储库
class MyCrudRepository<T> protected constructor(
        private val type: Class<T>,
) {
    companion object {
        inline fun <reified T : Any> of() = MyCrudRepository(T::class.java)
    }

    fun createTypeInstance() = type::class.createInstance()
}

在 JVM 上,对象的运行时类型会被删除,但 类 上的泛型类型不会。因此,如果您正在使用具体的专业化,则可以使用反射来检索类型参数:

import java.lang.reflect.*
​
abstract class AbstractRepository<T>
​
@Suppress("UNCHECKED_CAST")
fun <T> Class<out AbstractRepository<T>>.repositoryType(): Class<T> =
    generateSequence<Type>(this) {
        (it as? Class<*> ?: (it as? ParameterizedType)?.rawType as? Class<*>)
            ?.genericSuperclass
    }
        .filterIsInstance<ParameterizedType>()
        .first { it.rawType == AbstractRepository::class.java }
        .actualTypeArguments
        .single() as Class<T>
​
class IntRepository : AbstractRepository<Int>()
class StringRepository : AbstractRepository<String>()
interface Foo
class FooRepository : AbstractRepository<Foo>()
class Bar
class BarRepository : AbstractRepository<Bar>()
​
fun main() {
    println(IntRepository::class.java.repositoryType())
    println(StringRepository::class.java.repositoryType())
    println(FooRepository::class.java.repositoryType())
    println(BarRepository::class.java.repositoryType())
}
class java.lang.Integer
class java.lang.String
interface Foo
class Bar