You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring/Kotlin按嵌套泛型QueryHandler接口类型无法找到对应Bean问题求解

问题根源

JVM泛型擦除机制下,你传入的KClass<TResult>仅能代表原始类型,当TResult是List<UserDto>这类嵌套泛型类型时,resultType.java实际得到的是裸List类,嵌套的UserDto泛型信息被擦除,所以ResolvableType构造出的第二个泛型参数为List<?>,无法匹配实现类中List<UserDto>的完整类型。

可行解决方案

方案1:用Kotlin具体化泛型传递完整泛型信息(最推荐)

利用Kotlin inline + reified 具体化泛型特性,配合标准库typeOf() API(Kotlin 1.3及以上支持)拿到包含嵌套泛型的完整类型信息,再构造ResolvableType:

  1. 先新增一个inline重载方法,对外暴露使用:
import kotlin.reflect.full.typeOf
import org.springframework.core.ResolvableType

inline fun <reified TQuery : Query<TResult>, reified TResult : Any> dispatch(query: TQuery): TResult {
    // 拿到带完整嵌套泛型的KType
    return dispatch(query, TQuery::class, typeOf<TResult>())
}
  1. 修改原有dispatch方法的参数,接收KType作为结果类型入参:
override fun <TQuery : Query<TResult>, TResult : Any> dispatch(
    query: TQuery, 
    queryType: KClass<TQuery>, 
    resultType: KType
): TResult {
    val beanFactory = applicationContext.beanFactory

    // 分别构造两个泛型参数的完整ResolvableType
    val queryResolvableType = ResolvableType.forClass(queryType.java)
    val resultResolvableType = ResolvableType.forType(resultType.javaType)
    // 组装QueryHandler的完整泛型类型
    val handlerType = ResolvableType.forClassWithGenerics(
        QueryHandler::class.java,
        queryResolvableType,
        resultResolvableType
    )

    val beans = applicationContext.getBeanNamesForType(handlerType)
    val handler = beanFactory.getBean<QueryHandler<TQuery, TResult>>(beans.first())
    return handler.execute(query)
}

调用的时候直接用泛型指定即可,不需要手动传类型参数:

val users: List<UserDto> = dispatch(GetUsers())

方案2:手动校验泛型(兜底方案)

如果不想修改原有方法签名,可以先捞出所有QueryHandler实现类,反射校验泛型匹配:

override fun <TQuery : Query<TResult>, TResult : Any> dispatch(query: TQuery, queryType: KClass<TQuery>, resultType: KClass<TResult>): TResult {
    val handlers = applicationContext.getBeansOfType(QueryHandler::class.java)
    for ((_, handler) in handlers) {
        val handlerType = ResolvableType.forInstance(handler).`as`(QueryHandler::class.java)
        // 校验查询类型匹配
        if (handlerType.getGeneric(0).resolve() != queryType.java) continue
        // 校验结果类型匹配,支持嵌套泛型校验
        val handlerResultType = handlerType.getGeneric(1)
        val expectedResultType = ResolvableType.forType(resultType.java)
        if (handlerResultType.isAssignableFrom(expectedResultType)) {
            @Suppress("UNCHECKED_CAST")
            return handler as QueryHandler<TQuery, TResult>
        }
    }
    throw NoSuchElementException("No matching QueryHandler found")
}

这个方案性能略低于方案1,适合并发量不高的场景。

内容的提问来源于stack exchange,提问作者TheSpixxyQ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 22:18:04