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

原创
2015/11/28 18:44
阅读数 1.5W

业务背景:

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

代码:

先在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 aMETA-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





展开阅读全文
加载中

作者的其它热门文章

打赏
0
5 收藏
分享
打赏
0 评论
5 收藏
0
分享
返回顶部
顶部