使用@Query查询User列表触发ClassCastException异常求助
问题描述
将JSON字段的依赖从io.hypersistence:hypersistence-utils-hibernate-62替换为Hibernate原生的@JdbcTypeCode(SqlTypes.JSON)实现后,部署在Linux K8s环境时触发类型转换异常,本地MacOS环境可正常运行。
相关代码
仓库层实现
package com.user.Dao; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import com.user.Entities.User; @Repository public interface UserRepository extends CrudRepository<User,Long> { @Query(""" SELECT new com.user.UserProfileProjection(emails) FROM User WHERE id = :id""") Optional<UserProfileProjection> findProfileById(Long id); } public record UserProfileProjection(List<RestUserEmail> emails) { @SuppressWarnings("unchecked") public UserProfileProjection(Object emails) { this(((List<UserEmail>) emails).stream().map(e -> new RestUserEmail(e.email(), e.language())).toList()); } public record RestUserEmail(String email, Language language) }
修改前的User实体(使用Hypersistence工具)
import io.hypersistence.utils.hibernate.type.json.JsonBinaryType; import org.hibernate.annotations.Type; public class User extends AbstractAggregateRoot<User> { ... @Type(JsonBinaryType.class) private List<UserEmail> email; public record UserEmail(String email, Language language) { } }
修改后的User实体(使用Hibernate原生JSON支持)
import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; public class User extends AbstractAggregateRoot<User> { ... @JdbcTypeCode(SqlTypes.JSON) private List<UserEmail> email; public record UserEmail(String email, Language language) { } }
错误信息
java.lang.ClassCastException: class com.user.Dao.UserData$UserEmail cannot be cast to class java.util.List (package com.user.Dao.User$UserEmail is in unnamed module of loader org.springframework.boot.loader.launch.LaunchedClassLoader @f6f2d33; java.util.List is in module java.base of loader 'bootstrap')
解决方案
1. 对齐Spring Boot与Hibernate版本兼容性
确保使用的Spring Boot版本(建议3.2+)与Hibernate 6.x完全适配,部分旧版Spring Boot对Hibernate原生JSON类型的跨环境处理存在缺陷。
2. 调整JPQL查询逻辑
Hibernate原生JSON类型在JPQL中直接投影集合时,易出现序列化/反序列化的环境差异。改为先查询完整实体,再在业务层转换投影:
// 仓库层修改 @Query("SELECT u FROM User u WHERE id = :id") Optional<User> findByIdForProfile(Long id); // 业务层转换 public Optional<UserProfileProjection> getProfile(Long id) { return userRepository.findByIdForProfile(id) .map(user -> new UserProfileProjection(user.email())); }
3. 修复投影构造器的类型处理
原构造器依赖强制类型转换,跨环境类加载器可能导致类型识别异常,改为显式类型校验:
public UserProfileProjection(Object emails) { this(convertToRestEmails(emails)); } private static List<RestUserEmail> convertToRestEmails(Object emails) { if (emails instanceof List<?> list) { return list.stream() .filter(item -> item instanceof UserEmail) .map(item -> (UserEmail) item) .map(e -> new RestUserEmail(e.email(), e.language())) .toList(); } throw new IllegalArgumentException("Invalid emails type: " + emails.getClass()); }
4. 明确数据库JSON字段定义
在实体字段上添加columnDefinition,确保数据库端字段类型与Hibernate映射一致(以PostgreSQL为例):
@JdbcTypeCode(SqlTypes.JSON) @Column(columnDefinition = "jsonb") private List<UserEmail> email;
内容的提问来源于stack exchange,提问作者Duc Bui
相关产品推荐
相关产品推荐

