SpringBoot降至2.3.4.RELEASE时javax.persistence.Tuple.get报错求助
解决SpringBoot 2.3.4.RELEASE中使用javax.persistence.Tuple的访问器方法错误
问题描述
使用javax.persistence.Tuple从PostgreSQL查询数据时,SpringBoot 2.7.5版本运行正常,但降级到2.3.4.RELEASE后抛出以下错误:
java.lang.IllegalArgumentException: Invoked method public abstract java.lang.Object javax.persistence.Tuple.get(java.lang.String) is no accessor method! at org.springframework.data.projection.Accessor.(Accessor.java:50) ~[spring-data-commons-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
原因分析
SpringBoot 2.3.4.RELEASE对应的Spring Data Commons版本是2.3.x,这个版本的Accessor类对访问器方法的校验逻辑比较严格:它要求方法符合JavaBean getter规范(比如getXxx()形式、无参数)。而Tuple.get(String)是带参数的方法,不符合该校验规则,因此被判定为非法的访问器方法。
Spring Data后续版本(比如对应SpringBoot2.7的版本)修复了这个问题,能正确识别并处理Tuple类型的方法调用。
解决方案
方案1:改用DTO或接口投影替代Tuple
这是最稳妥的方式,避免直接使用Tuple:
- DTO方式:创建包含目标字段的DTO类,在JPQL中使用构造函数查询返回该DTO:
// DTO类 public class UserDTO { private Long id; private String name; public UserDTO(Long id, String name) { this.id = id; this.name = name; } // 按需添加getter方法 } // Repository中的查询方法 @Query("select new com.example.dto.UserDTO(u.id, u.name) from User u where u.id = ?1") UserDTO findUserById(Long id); - 接口投影方式:定义包含对应getter方法的接口,Spring Data会自动映射查询结果:
public interface UserProjection { Long getId(); String getName(); } // Repository中的查询方法 @Query("select u.id as id, u.name as name from User u where u.id = ?1") UserProjection findUserProjectionById(Long id);
方案2:自定义Repository实现手动处理Tuple
如果必须使用Tuple,可以自定义Repository的实现类,手动处理查询结果:
// 自定义Repository接口 public interface CustomUserRepository { Tuple findUserTupleById(Long id); } // 实现类 @Repository public class CustomUserRepositoryImpl implements CustomUserRepository { @PersistenceContext private EntityManager entityManager; @Override public Tuple findUserTupleById(Long id) { Query query = entityManager.createQuery("select u.id, u.name from User u where u.id = :id", Tuple.class); query.setParameter("id", id); return (Tuple) query.getSingleResult(); } } // 主Repository继承自定义接口 public interface UserRepository extends JpaRepository<User, Long>, CustomUserRepository { }
方案3:先修复Gradle依赖冲突
你的build.gradle配置存在依赖冲突问题:
implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}") implementation 'org.springframework.boot:spring-boot-starter-web:2.7.0'
同时声明了两个不同版本的spring-boot-starter-web,会导致依赖混乱,必须统一版本。删掉第二个依赖,全部使用${springBootVersion}(即2.3.4.RELEASE)。
额外说明
不建议单独升级Spring Data Commons版本适配,因为SpringBoot的依赖管理是统一的,单独升级可能引发其他依赖兼容性问题,优先采用前两种方案。
内容的提问来源于stack exchange,提问作者Sanjay Naik
相关产品推荐
相关产品推荐

