我遇到了一个非常奇怪的异常,我不知道如何找到原因。
业务背景:添加商品并同时显示其价目表,对于差异级别用户,商品有5个价格。
在控制器中,首先使用推土机将goodForm转换为商品,然后调用goodsService保存商品。在goodsService中,保存商品,遍历商品价格清单并填充goodsId到商品价格后,
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());
但是它抛出异常:
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]
此错误消息让我感到非常困惑。另外我写了一个单元测试想重复一次,但是失败了。
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()));
运行此单元测试,它执行正常。那么,为什么在实际的网络情况下(Spring boot + Jpa)失败了,但是在单元测试情况下还可以呢?
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
如果生成打包的jar,请执行此jar
java -jar target/myapp.jar
在这种情况下,没有以上例外。
我在pom.xml中注释了spring-boot-devtools,然后启动了应用程序,没有上面的异常。
默认情况下,将使用“重新启动”类加载器加载IDE中任何打开的项目,而使用“基本”类加载器加载任何常规.jar文件。如果您在一个多模块项目上工作,并且没有将每个模块都导入到IDE中,则可能需要自定义内容。为此,您可以创建一个META- INF / spring-devtools.properties文件。 spring- devtools.properties文件可以包含restart.exclude。然后重新启动。前缀属性。include元素是应上拉到“重新启动”类加载器中的项目,而exclude元素是应下推到“基本”类加载器中的项目。该属性的值是一个将应用于类路径的正则表达式模式。
默认情况下,将使用“重新启动”类加载器加载IDE中任何打开的项目,而使用“基本”类加载器加载任何常规.jar文件。如果您在一个多模块项目上工作,并且没有将每个模块都导入到IDE中,则可能需要自定义内容。为此,您可以创建一个META- INF / spring-devtools.properties文件。
spring- devtools.properties文件可以包含restart.exclude。然后重新启动。前缀属性。include元素是应上拉到“重新启动”类加载器中的项目,而exclude元素是应下推到“基本”类加载器中的项目。该属性的值是一个将应用于类路径的正则表达式模式。
我的解决方案:放入META-INF/spring-devtools.properties资源文件夹,然后添加此内容
META-INF/spring-devtools.properties
restart.include.dozer=/dozer-5.5.1.jar
请参阅:http : //docs.spring.io/spring- boot/docs/current/reference/htmlsingle/#using-boot-devtools-customizing- classload