Kotlin Hibernate 泛型KClass查询列表时Criteria类型不匹配报错
报错本质
- 当传入泛型化的
KClass<*>时,编译器对criteriaBuilder.createQuery(clazz.java)的泛型推导出现偏差,最终生成的CriteriaQuery被识别为CriteriaQuery<Nothing>类型。 - 此时
criteria.select()方法要求传入与CriteriaQuery泛型完全匹配的Selection<out Nothing>,但criteria.from(clazz.java)返回的Root<out Any>泛型边界和要求的Nothing不匹配,直接触发类型校验报错。 - 传入固定实体类(如
Country::class.java)时,编译器可以明确推导出匹配的CriteriaQuery<Country>、Root<Country>类型,泛型链路完全对齐,因此不会出现报错。
修复方案
基础兼容实现
手动修正泛型推断的偏差,对齐类型边界,最小改动消除编译报错:
fun getListSize(clazz: KClass<*>): Int { hibernate.openSession().use { session -> val cb = session.criteriaBuilder // 显式指定CriteriaQuery的泛型为Any,消除Nothing的错误推断 val criteria = cb.createQuery(Any::class.java) as CriteriaQuery<Any> val root = criteria.from(clazz.java) criteria.select(root) val query = session.createQuery(criteria) return query.resultList.size } }
注意:原实现缺少Session资源关闭逻辑,新增的use代码块会在方法逻辑执行完成后自动关闭会话,避免数据库连接泄漏。
性能优化实现
原实现会把实体全量查询到内存后再统计大小,数据量较大时会占用大量内存,可直接调整为数据库层面执行count统计,性能更高:
fun getListSize(clazz: KClass<*>): Long { hibernate.openSession().use { session -> val cb = session.criteriaBuilder val criteria = cb.createQuery(Long::class.java) val root = criteria.from(clazz.java) // 直接在数据库端统计实体总数,无需拉取全量实体数据到内存 criteria.select(cb.count(root)) return session.createQuery(criteria).singleResult } }
额外说明
- 不要为了绕开报错对所有类型加无边界强制转换,避免后续运行时出现类转换异常。
- 泛型场景下的Criteria查询,尽量通过显式指定Query的泛型参数来消除编译器的不确定推断,比无意义的强转更稳定。
内容的提问来源于stack exchange,提问作者displayThisName
相关产品推荐
相关产品推荐

