SpringBoot+JPA查询报同类型ClassCastException问题求助
问题现象
应用抛出类转换异常:
java.lang.ClassCastException: class com.estrelladekleene.safetycar.dto.DriverDTO cannot be cast to class com.estrelladekleene.safetycar.dto.DriverDTO (com.estrelladekleene.safetycar.dto.DriverDTO is in unnamed module of loader 'app'; com.estrelladekleene.safetycar.dto.DriverDTO is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @47e566be)
场景说明:使用Spring Boot + Hibernate JPA + SQL Server开发REST API,调用按手机号查询的getDriverByPhoneNumber方法,或用entityManager.find查询单条记录时触发异常,但全量查询getAllDrivers可正常执行。
原因分析
这个异常的核心是同一个类被两个不同的类加载器加载:一个是系统类加载器(app loader),另一个是Spring Boot DevTools的RestartClassLoader。JVM规则中,即使类的全限定名完全一致,只要加载它的类加载器不同,就会被判定为两个完全不同的类,进而导致类型转换失败。
全量查询暂时正常,大概率是因为该查询返回的实例都来自同一个类加载器,没有触发跨加载器的类型交互,问题未暴露。
解决方案
方案1:直接禁用Spring Boot DevTools
如果不需要热重启开发功能,直接移除项目中的DevTools依赖:
- Maven项目:移除pom.xml中的对应依赖块
<!-- 移除该依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>
- Gradle项目:移除build.gradle中的对应配置
// 移除该依赖 developmentOnly 'org.springframework.boot:spring-boot-devtools'
方案2:配置DevTools排除指定类(保留热重启)
如果需要保留热重启功能,在src/main/resources/application.properties中添加配置,将DriverDTO所在的包排除在RestartClassLoader的加载范围外:
spring.devtools.restart.exclude=com/estrelladekleene/safetycar/dto/**
也可以直接排除整个DTO包,避免后续其他DTO类出现同类问题。
额外修复:SQL注入风险
你的getDriverByPhoneNumber方法存在严重的SQL注入隐患,禁止直接拼接字符串到JPQL语句中,改用参数绑定写法:
public DriverDTO getDriverByPhoneNumber(String phoneNumber) { return entityManager.createQuery( "SELECT d FROM DriverDTO d WHERE d.phoneNumber = :phoneNumber", DriverDTO.class) .setParameter("phoneNumber", phoneNumber) .getSingleResult(); }
这种写法不仅能避免SQL注入,还能兼容手机号包含特殊字符的场景。
内容的提问来源于stack exchange,提问作者Gaspar Zanini

