从未修饰的类型参数实例化类

时间:2020-09-21 13:10:58

标签: kotlin generics orm spring-data jasync-sql

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

在给定的条件下,如何实例化类型为T的类的实例 非修饰类型参数T

众所周知的Spring Data project manages this,您可以在它们的CrudRepository<T, ID>界面中看到它,该界面使用类型参数T进行了参数设置,并公开了返回类型为T的实例的方法。我查看了源代码,但收效不大,但是某处它必须能够在运行时实例化类型为T的类,尽管事实上T删除。

当我查看自己的AbstractRepository<T>抽象类时,我不知道如何获取对T的构造函数的引用,因为它需要访问T::class.constructors,除非可以理解的是失败T是一种修正类型。鉴于只能在内联函数的参数中使用类型化的类型,我对它的工作方式有点迷惑了。

2 个答案:

答案 0 :(得分:1)

在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

答案 1 :(得分:0)

在您自己的CrudRepository中,您可以添加一个带有内联乐趣的伴侣对象,该对象通过将相应的类传递给它来实例化您的存储库。

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