2015-11-27 27 views
6

Çok garip bir istisna ile karşılaştım ve sebebini nasıl bulacağımı bilmiyorum.Spring boot devtools ile ilgili bir dozer haritası istisnası

İş dünyası: Mal ekle ve bu arada fiyat listesi, bir malın farklı seviyelerdeki kullanıcı için 5 fiyatı var.

Denetleyicide, önce goodForm'u dozer ile mallara dönüştürün, ardından malları kaydetmek için malServis'i arayın. goodsService yılında mal, kastetmek mal fiyat listesi kaydetme ve

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()); 

, mal fiyatına goodsId doldurmak Ama istisna sonrası:

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] 

Bu hata mesajı bana çok karışık hissediyorum edelim. Ayrıca bunu tekrarlamak isteyen bir birim testi yazdım ama başarısız oldu.

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())); 

Bu birim sınamasını çalıştırın, tamamlandı. Peki, neden gerçek web durumunda (Spring boot + Jpa) başarısız, ama birim test durumunda, tamam mı?


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 

Ben paketlenmiş kavanoz oluşturulan, o zaman yukarıdaki istisnasız Bu durumda bu kavanoz

java -jar target/myapp.jar 

yürütün.


Ve pom.xml'Bu yay çizme-DevTools'un yorumladı ve ardından yukarıdaki istisnasız uygulaması başladı.

+9

senin de aynı sınıfı yüklemek eğer böyle bir istisna vardı sadece zaman:

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

bakınız META-INF/spring-devtools.properties iç kaynaklar klasörünü koymak ve bu içerik eklemek 2 farklı sınıf yükleyiciyle. Her nesnenin sınıf yükleyicisini yazdırmayı deneyebilir misiniz? –

+5

Daha sonra aynı sınıf iki farklı sınıf yükleyici tarafından yüklendi. İlk ölçüt, sınıfı bir yerde tek bir kavanoza sokmaktır. –

+0

@Wim Deblauwe Yolunuzu denedim, lütfen bu yazının altındaki ek içeriklerime bakın – zhuguowei

cevap

8

Varsayılan olarak, IDE'nizdeki herhangi bir açık proje “restart” classloader kullanılarak yüklenecek ve herhangi bir normal .jar dosyası “base” classloader kullanılarak yüklenecektir. Çok modüllü bir projede çalışıyorsanız ve her modül IDE'nize aktarılmazsa, şeyleri özelleştirmeniz gerekebilir. Bunu yapmak için bir META-INF/spring-devtools.properties dosyası oluşturabilirsiniz.

Spring-devtools.properties dosyası restart.exclude içerebilir. ve restart.include. önekli özellikler. Dahil olan öğeler, “yeniden başlat” sınıf yükleyicisine çekilmesi gereken öğelerdir ve dışlama öğeleri “temel” sınıf yükleyicisine indirilmesi gereken öğelerdir. Mülkün değeri, sınıf yoluna uygulanacak bir regex modelidir.

Benim Çözüm: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-devtools-customizing-classload

+1

Eğer dozer-yayı kullanırsanız, bunu da ekleyin: restart.include.dozer-spring =/dozer-spring-5.5.1.jar – cLyric

0

Burada iki farklı ClassLoader kullanıyorsunuz. İki farklı ClassLoader ile yüklenmiş bir Class10, JVM tarafından iki farklıClass olarak kabul edilir.

Bunu düzeltmek için çözüm basittir: Interface kullanın.

Arabirimler bu sorunu özümseyebilir ve uygulamayı doğrudan başvurmadığınız sürece ClassLoaders arasında uyguladıkları nesneyi sınırlama olmaksızın değiştirebilirsiniz.

+1

İlk bölümde sizinle birlikte gelirim ama ikinci bölümünüz tamamen yanlış. Bir arabirim, bir sınıf yükleyici görünümünden de, bir sınıf dosyasıdır. Yani classLoader1.loadClass ("... MyInterface")! = ClassLoader2.loadClass ("... MyInterface") '. –

+0

Oh haklısın, ben öyle demek istemedim, ama tamamen bu şekilde çıktı. Daha net hale getirmek için ifademi düzenledim. –

+1

Sanırım bu hala belirsiz. OP'deki çoğaltma işaretimi okursanız, bunun bir arayüzle ilgili olduğunu görürsünüz. Arayüzü hala iki farklı sınıf yükleyiciyle yüklediğiniz sürece, bir arayüz kullanmanın yararı olmaz. _common ana sınıfı loader_'dan bir arabirim veya üst sınıfın yardımcı olacağı durumlar olduğunu biliyorum, ancak mevcut sorunun bu durumlardan birine ait olduğunu düşünmüyorum. Yine de bir örnekle yanlış olduğunu ispat edebilirsiniz ... –