Kotlin扩展函数未调用Hibernate/JPA中重写的findById方法问题
问题原因及解决方案
核心原因:Kotlin扩展函数的静态分发机制
Kotlin扩展函数属于静态分发,编译器会根据调用时接收者的静态类型(而非实际运行时类型)解析调用的方法:
- 直接调用
fooRepository.findById(id)时,fooRepository的静态类型是你的自定义Repository接口(如FooRepository),Spring生成的代理类实现了该接口,因此会触发你重写的带@Query的findById方法。 - 你的
findByIdOrNull是定义在CrudRepository<T, ID>上的扩展函数,调用fooRepository.findByIdOrNull(id)时,编译器会将扩展函数内部的findById解析为CrudRepository接口的默认实现(未包含deletedAt is null的过滤逻辑),而非你在自定义Repository中重写的方法,因此会查询到已标记删除的实体。
解决方案
方案1:将扩展函数定义在自定义Repository接口上
把扩展函数的接收者改为具体的自定义Repository接口,让编译器解析到你重写的findById方法:
fun FooRepository.findByIdOrNull(id: UUID): Foo? = findById(id).orElse(null)
方案2:定义通用BaseRepository接口并扩展
如果多个自定义Repository都需要该扩展功能,可以先定义通用BaseRepository接口,让所有自定义Repository继承它,再将扩展函数定义在BaseRepository上:
// 定义通用BaseRepository interface BaseRepository<T, ID> : CrudRepository<T, ID> { override fun findById(id: ID): Optional<T> } // 自定义Repository继承BaseRepository interface FooRepository : BaseRepository<Foo, UUID> { @Query("from Foo v where v.id = :id and v.deletedAt is null") override fun findById(id: UUID): Optional<Foo> } // 扩展函数定义在BaseRepository上 fun <T, ID> BaseRepository<T, ID>.findByIdOrNull(id: ID): T? = findById(id).orElse(null)
这样任意自定义Repository调用findByIdOrNull时,都会触发各自重写的findById方法。
内容的提问来源于stack exchange,提问作者FeXseven
相关产品推荐
相关产品推荐

