Kotlin+Quarkus环境下如何继承泛型类并传递PanacheRepository
问题核心原因
- GenericResource未做泛型抽象,硬编码了
User类型和PanacheRepository<Any>,既不通用也和实际传入的Repository泛型不匹配 - UserResource构造参数传值错误,应该注入
UserRepository实例传给父类,而非User实体实例 - Kotlin泛型默认是不变性,
PanacheRepository<User>无法直接赋值给PanacheRepository<Any>
正确实现方案
1. 泛型化通用资源类
首先将GenericResource改为抽象泛型类,支持任意实体类型复用:
// 泛型参数T为实体类型,ID如果全是UUID可以固定,需要兼容其他ID类型可以再加ID泛型参数 abstract class GenericResource<T>( val repository: PanacheRepository<T> ) { @GET @Produces(MediaType.APPLICATION_JSON) fun findAll() : FindAllResponse = try { FindAllSuccess(repository.listAll()) } catch (e: Exception) { FindAllFailure(e) } @POST @Transactional fun add( @Valid entity: T ) : AddResponse = try { repository.persist(entity) AddSuccess(entity) } catch (e: Exception) { AddFailure(e) } @GET @Path("/{id}") fun findById( @PathParam("id") id : UUID ) : FindResponse = try { FindSuccess( repository.find("id", id).firstResult() ) } catch (e: NotFoundException) { FindFailure(e) } // 字段差异大的场景可把update方法声明为abstract强制子类实现 @PATCH @Transactional @Path("/{id}") open fun update( @PathParam("id") id : UUID, entity: T ) : UpdateResponse = try { if (entity is User) { entity.id?.let { userId -> entity.fullName?.let { fullName -> entity.email?.let { email -> repository.update("fullName = ?1, email = ?2 where id = ?3", fullName, email, userId) } } } } UpdateSuccess(entity) } catch (e: Exception) { UpdateFailure(e) } @DELETE @Transactional @Path("/{id}") fun delete( @PathParam("id") id : UUID ) : DeleteResponse = try { repository.delete("id", id) DeleteSuccess("资源删除成功") } catch (e: Exception) { DeleteFailure(e) } }
说明:如果响应类FindAllResponse/AddResponse等也需要通用,可以同步给这些类加上泛型参数,适配不同实体的返回
2. 实现User资源子类
注入UserRepository传递给父类,业务注解加在子类上即可:
@Path("/users") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) class UserResource @Inject constructor( private val userRepository: UserRepository ) : GenericResource<User>(userRepository) { // 特殊业务需求可在这里重写父类方法 }
3. UserRepository保持原有逻辑不变
@ApplicationScoped class UserRepository : PanacheRepository<User>
额外优化建议
- 如果不同实体的ID类型不一致,可以给
GenericResource增加第二个泛型参数ID,替换掉固定的UUID类型 - 对于字段差异较大的实体操作,可将对应方法声明为
abstract,强制子类实现对应逻辑 - 异常捕获可以更精细化,避免直接捕获所有
Exception导致问题排查困难
内容的提问来源于stack exchange,提问作者rjjdv
相关产品推荐
相关产品推荐

