问题
I have encountered a very strange exception, and I don't know how to find the reason.
Business background: Add goods and meantime it's price list, a goods have 5 price for diff level user.
In controller, first convert goodForm to goods by using dozer, then call goodsService to save goods. In goodsService after saving goods, traversal goods price list and populate goodsId to goods price,
GoodsForm:
@Mapping("priceList")
List<GoodsPriceForm> goodsPriceFormList;
Goods:
List<GoodsPrice> priceList;
Controller:
Goods goods = BeanMapper.map(goodsForm, Goods.class);
goodsService.saveGoods(adminId, goods);
GoodsService:
goodsDao.save(goods);
goods.getPriceList().forEach(p -> p.setGoodsId(goods.getId()));
goodsPriceDao.save(goods.getPriceList());
But it throw exception:
2015-11-27 17:10:57,042 [http-nio-8081-exec-8] ERROR o.a.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: com.foo.goods.model.GoodsPrice cannot be cast to com.foo.goods.model.GoodsPrice] with root cause
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]
This error message let me feel very confused. In addition I write a unit test wanted to repeat this, but failed.
GoodsForm form = new GoodsForm();
form.setGoodsPriceFormList(Lists.newArrayList(new GoodsPriceForm((byte) 1, BigDecimal.valueOf(10)),
new GoodsPriceForm((byte) 2, BigDecimal.valueOf(9)),
new GoodsPriceForm((byte) 3, BigDecimal.valueOf(8))));
Goods goods = BeanMapper.map(form, Goods.class);
goods.getPriceList().forEach(p -> p.setGoodsId(goods.getId()));
Run this unit test, it executed ok. So why in real web situation(Spring boot + Jpa) it's failed, but in unit test situation it's ok?
Controller:
System.out.println("PriceList: " + goods.getPriceList().getClass().getClassLoader());//PriceList: null
System.out.println(goods.getPriceList().get(0).getClass().getClassLoader()); //java.lang.ClassCastException: com.foo.goods.model.GoodsPrice cannot be cast to com.foo.goods.model.GoodsPrice
If I generated a packaged jar, then execute this jar
java -jar target/myapp.jar
In this case without above exception.
And I commented spring-boot-devtools in pom.xml, then started application, without above exception.
回答1:
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.
My Solution: put META-INF/spring-devtools.properties
inside resources folder, and add this content
restart.include.dozer=/dozer-5.5.1.jar
Please see : http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-devtools-customizing-classload
回答2:
You are using two different ClassLoader
here. An identical Class
loaded with two different ClassLoader
is considered as two different Class
by the JVM.
The solution to fix this is simple : Use an Interface
.
Interfaces are able to abstract this problem, and you can interchange the object they implement between ClassLoaders without limitation, as long as you don't reference the implementation directly.
来源:https://stackoverflow.com/questions/33955542/a-dozer-map-exception-related-to-spring-boot-devtools