假设以下(jdbc)存储库:
interface Repo : CrudRepository<MyType, Long> {
@Query("select * from blabla")
fun abc(): List<MyType>
}
对于方法abc()
和父接口中包含的方法,Repo
接口的自动生成运行时实现都知道如何在一定的限制下将结果集序列化到MyType
的实例中。
Spring如何在运行时从泛型参数访问类型信息?它如何仅仅基于接口中提供的类型信息来创建正确的运行时类型列表?
我的理解是,我不会从下面的mapV1()
这样的签名中获得足够的信息来实例化我的结果,因此我需要引入第二个类型为Class<T>
的参数,如mapV2()
所示:
class Mapper {
fun <T> mapV1(source: Any): T {
/*
try to instantiate a result
of type T reflectively
*/
}
fun <T> mapV2(source: Any, klass: Class<T>): T {
/*
try to instantiate a result
of type T reflectively
*/
}
}
Spring避免了这个问题。
并非所有类型信息都被擦除。诸如方法的返回类型和参数类型、超类和超接口、字段类型等都作为元数据存储在类文件中。Java反射API允许您获取它们:
// note that the "as ParameterizedType" cast only succeeds if the type is generic
println((Repo::class.java.genericInterfaces[0] as ParameterizedType)
.actualTypeArguments.toList()) // [class MyType, class java.lang.Long]
println((Repo::class.java.getDeclaredMethod("abc").genericReturnType as ParameterizedType)
.actualTypeArguments.toList()) // [class MyType]
你也可以用Kotlin反射API做这件事:
println(Repo::class.supertypes[0].arguments) // [MyType, kotlin.Long]
println(Repo::class.declaredMembers.find { it.name == "abc" }?.returnType?.arguments) // [MyType]
但是在mapV1
的情况下,您可以获得的唯一元数据只是"T
",这不是很有用。你无法获得调用者传递给它的参数。