您的位置:首页 > 编程语言 > Java开发

使用了Spring boot devtools, dozer转换嵌套对象失败解决记录

2015-11-28 18:44 441 查看
业务背景:

添加商品以及价格,一个商品会有多个价格(针对不同用户等级).

代码:

先在controller中使用dozer将goodsForm-->Goods,然后保存商品, 之后遍历商品价格列表,注入商品ID,接着保存商品价格.

GoodsForm:
List<GoodsPriceForm> priceList;
Goods:
List<GoodsPrice> priceList;

Controller:
Goods goods = BeanMapper.map(goodsForm, Goods.class);
save(goods);
goods.getPriceList().forEach(p->p.setGoodsId(goods.getId()));
save(goods.getPriceList());

在遍历商品价格列表时报错, 错误信息:

java.lang.ClassCastException: com.foo.goods.model.GoodsPrice cannot be cast to com.foo.goods.model.GoodsPrice
at com.foo.goods.service.GoodsService$$Lambda$11/310447431.accept(Unknown Source) ~[na:na]
at java.util.ArrayList.forEach(ArrayList.java:1249) ~[na:1.8.0_51]
at com.foo.goods.service.GoodsService.saveGoods(GoodsService.java:34) ~[classes/:na]

对这一异常描述有些摸不着头脑, 经提醒有可能是不同的类加载器加载导致, 在Eclipse debug模式中Expression视图下,输出了goods和goodsPrice的类加载器名

Goods: org.springframework.boot.devtools.restart.classloader.RestartClassLoader@41aa15ea
GoodsPrice:  sun.misc.Launcher$AppClassLoader@58644d46

果然涉及到不同的类加载器.

尝试了在pom.xml中注释掉spring-boot-devtools, 再启动后没有上述异常. 但如何在保留devtools的情况下解决该问题呢? 查询官方文档:

By default, any open project in your IDE will be loaded using the “restart” classloader, and any regular
.jar
file will be loaded using the “base” classloader. If you work on a multi-module project, and not each module is imported into your IDE, you may need to customize things. To do this you can create a
META-INF/spring-devtools.properties
file.
The
spring-devtools.properties
file can contain
restart.exclude.
and
restart.include.
prefixed properties. The
include
elements are items that should be pulled-up into the “restart” classloader, and the
exclude
elements are items that should be pushed down into the “base” classloader. The value of the property is a regex pattern that will be applied to the classpath.

于是在工程的resources目录下添加了META-INF/spring-devtools.properties,内容为

restart.include.dozer=/dozer-5.5.1.jar

即dozer代码也使用RestartClassLoader,可以解决上述问题.

补充:

在该工程中的Application类中有如下一段代码

@Bean
public Mapper fooDozerBeanMapper() {
DozerBeanMapper mapper = BeanMapper.getDozerBeanMapper();
List<String> mappingFiles = Lists.newArrayList(mapper.getMappingFiles());
mappingFiles.add("foo-dozer-custom-convert.xml");
mapper.setMappingFiles(mappingFiles);
return mapper;
}

其中BeanMapper是依赖另一个工程(bar), 当在Eclipse中关闭该依赖工程(bar)后, 会报错

Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of org/springframework/boot/devtools/restart/classloader/RestartClassLoader) previously initiated loading for a different type with name "org/dozer/DozerBeanMapper"
at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_05]
at java.lang.ClassLoader.defineClass(ClassLoader.java:760) ~[na:1.8.0_05]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_05]

解决方法

修改spring-devtools.properties,再增加一个配置

restart.include.bar=/bar.jar
restart.include.dozer=/dozer-5.5.1.jar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息