QuerydslPredicateExecutor搭配JpaRepository使用抛出IllegalAccessException如何解决?
问题根本原因
QueryDSL 5.0版本的Kotlin代码生成器默认生成的Q类静态实例字段为private static final修饰,而Spring Boot 2.6.0自带的Spring Data JPA 2.6.0版本中,SimpleEntityPathResolver会通过反射读取Q类的公共静态实例字段来构造实体路径,没有处理私有字段的访问权限,因此触发了IllegalStateException异常。
直接使用JPAQuery能正常运行的原因是:代码中显式引用QWorkplace.workplace属于Kotlin编译期的直接访问,同包下的私有成员允许直接访问,不需要反射调用,因此不会触发权限校验问题。
可用解决方案
方案1:修改QueryDSL代码生成配置,生成公共字段的Q类
在Gradle的QueryDSL Kotlin代码生成配置中添加publicFields = true参数,示例配置片段如下:
querydsl { jpa = true kotlin = true publicFields = true // 新增这行配置 }
配置后重新clean build项目,生成的Q类静态实例就会变成public修饰,Spring Data可以正常反射读取。
方案2:自定义可访问私有字段的EntityPathResolver
注册自定义的EntityPathResolver Bean,覆盖默认实现,反射读取字段时主动开启访问权限:
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.data.querydsl.EntityPathResolver import com.querydsl.core.types.EntityPath @Configuration class QuerydslConfig { @Bean fun entityPathResolver(): EntityPathResolver { return EntityPathResolver { entityClass -> val qClass = Class.forName("${entityClass.packageName}.Q${entityClass.simpleName}") val field = qClass.getDeclaredField(entityClass.simpleName.decapitalize()) field.isAccessible = true field.get(null) as EntityPath<*> } } }
Spring Data会自动使用这个自定义的Resolver来获取Q类实例,无需修改其他业务代码。
方案3:降级QueryDSL版本到4.4.x
QueryDSL 4.x版本的Kotlin代码生成器默认生成的Q类静态实例为public修饰,和Spring Data JPA 2.6.x版本天然兼容,无需额外配置即可正常使用QuerydslPredicateExecutor。
内容的提问来源于stack exchange,提问作者Saecki
相关产品推荐
相关产品推荐

