Spring 存储库如何实例化查询方法的结果?

How do Spring repositories instantiate results from query methods?

假设以下 (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 避免了这个问题。

并非所有类型信息都被删除。 return 类型和方法的参数类型、superclass 和超级接口、字段类型等作为元数据存储在 class 文件中。 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”,这不是很有用。您无法获取调用者传递给它的参数。