我正在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
是一种修正类型。鉴于只能在内联函数的参数中使用类型化的类型,我对它的工作方式有点迷惑了。
答案 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()
}