Bulldozer sorting map exception related to Spring loading devtools

I came across a very strange exception, and I do not know how to find the cause.

Business: Add a product, as well as its price list, the product has 5 prices for the user level level.

In the controller, first convert goodForm into products using a bulldozer, then call the product service to save the product. In the product Service after the storage of goods, the price list of price lists of goods and the settlement of goods From the goods at a 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 this is an exception:

 2015-11-27 17:10:57,042 [http-nio-8081-exec-8] ERROR oacatalina.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 makes me feel very confused. In addition, I am writing unit test 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 will execute ok. So why in a real web situation (Spring boot + Jpa) it failed, but in the unit test state is this normal?


 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, run this jar

 java -jar target/myapp.jar 

In this case, without exceeding the exception.


And I commented on spring-boot-devtools in pom.xml and then started the application without exception.

+6
source share
2 answers

By default, any open project in your IDE will be loaded using the "reload" class loader, and any regular .jar file will be loaded using the "base" class loader. If you are working on a project with multiple modules, and not every module is imported into your IDE, you may need to configure everything. To do this, you can create the META-INF / spring -devtools.properties file.

The spring -devtools.properties file may contain a restart.exclude file. and restart.include. prefix properties. The include elements are the elements that should be pulled into the "reload" class loader, and the exclude elements are the elements that should be placed in the "base" class loader. The property value is a regular expression pattern that will be applied to the class path.

My solution: put META-INF/spring-devtools.properties internal resource folder and add this content

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

See: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-devtools-customizing-classload

+8
source

Here you are using two different ClassLoader . An identical Class loaded with two different ClassLoader is considered by the JVM as two different Class .

The solution for this is simple: use Interface .

Interfaces can abstract this problem, and you can exchange the object that they implement between ClassLoaders, without limitation, if you do not refer directly to the implementation.

0
source

All Articles