Dozer抛出MappingException:setEstado同类型匹配异常排查求助
这种问题我之前踩过好几次坑,乍一看预期和实际类型完全一致,但Dozer偏说类型不匹配,核心原因十有八九是类加载器冲突——JVM判断两个类是否相等,不仅看全限定类名,还要看加载它们的类加载器是否相同。哪怕是同一个类文件,被不同类加载器加载,JVM都会认为是两个不同的类型。
结合你提到的Spring Boot配置、Hibernate EAGER加载和Maven Profiles怀疑,给你几个排查和解决方向:
1. 先确认类加载器是否真的不一致
先写两行代码打个日志,对比实际对象的类加载器和TbEstadoDto的类加载器:
// 在报错的地方附近加这段代码 Object actualObj = ...; // 你要映射的那个对象 System.out.println("实际对象类加载器: " + actualObj.getClass().getClassLoader()); System.out.println("TbEstadoDto类加载器: " + TbEstadoDto.class.getClassLoader());
如果输出的类加载器不一样,那就能实锤是类加载器的问题了,接下来对应下面的方案解决。
2. 排查Maven Profiles过滤的影响
你怀疑Profiles过滤的问题是合理的,可能的情况包括:
- 不同Profiles的打包配置中,重复将
TbEstadoDto类打包到了不同的目录或jar中,导致类被多次加载 - 过滤规则(比如
resource标签的filtering配置)意外修改了类文件的字节码,导致类加载时出现异常
解决办法:
- 检查
target/classes目录下是否存在多个路径的TbEstadoDto.class文件 - 运行
mvn clean package -P你的Profile后,解压生成的jar包,查看是否有重复的es/dominion/alert/util/dtos/TbEstadoDto.class - 调整pom.xml中的Profiles配置,确保同一类只被打包一次,避免不必要的文件过滤(类文件一般不需要过滤)
3. 调整Dozer的类加载器配置
Spring Boot中,Dozer默认的类加载器可能和Spring容器的上下文类加载器不一致,导致它加载的TbEstadoDto和业务代码中加载的不是同一个类。
修改你的Dozer Bean配置,强制让它使用当前线程的上下文类加载器(也就是Spring的类加载器):
@Bean public Mapper mapper() { DozerBeanMapper mapper = new DozerBeanMapper(Arrays.asList("dozerMapping.xml")); // 设置类加载器为Spring上下文类加载器 mapper.setClassLoader(Thread.currentThread().getContextClassLoader()); return mapper; }
4. 排查Hibernate代理类的干扰
虽然报错里显示实际类型是TbEstadoDto,但Hibernate的EAGER加载可能生成了动态代理类(比如继承自TbEstadoDto的代理),只是toString的时候显示的是原类名。你可以打印actualObj.getClass().getName()看看是否有$Proxy之类的后缀。
如果是代理类的问题,需要给Dozer配置Hibernate代理解析器:
- 首先引入dozer-hibernate依赖:
<dependency> <groupId>net.sf.dozer</groupId> <artifactId>dozer-hibernate</artifactId> <version>你的Dozer版本对应的适配版本</version> </dependency>
- 然后在
dozerMapping.xml中添加配置:
<configuration> <proxy-resolver>org.dozer.hibernate.HibernateProxyResolver</proxy-resolver> <!-- 其他配置保持不变 --> </configuration>
5. 检查类路径依赖冲突
用Maven命令查看依赖树,排查是否有重复的依赖引入了同一个类:
mvn dependency:tree
如果发现有不同的jar包都包含了TbEstadoDto类,需要排除重复的依赖,确保只有一个来源。
内容的提问来源于stack exchange,提问作者Observer

