1.背景
项目需要使用到一个实体映射工具(Entity Mapping)。例如:实体A、B,字段名称全部一样,将实体A中的字段值,全部复制到实体B中。
调查过程中,采用orika-mapper框架,本地单元测试也表现良好。
2.问题
当将使用orika代码,在测试环境运行,转换过程报NullPointerException。详细异常堆栈信息见下方
java.lang.RuntimeException: ma.glasnost.orika.MappingException: While attempting the following mapping:
sourceType = com.ctrip.corp.hotelbooking.bookcommon.db.model.corporderdb.CorpOrders
destinationType = com.ctrip.corp.hotelbooking.bookcommon.db.entity.corporderdb.HTLCCorpOrders
Error occurred: java.lang.NullPointerException
-------------------------------------------------------------
Unenhance strategy: ma.glasnost.orika.unenhance.BaseUnenhancer@1e408a3b
-----end dump of current state-------------------------------
at ma.glasnost.orika.impl.generator.MapperGenerator.build(MapperGenerator.java:105)
at ma.glasnost.orika.impl.DefaultMapperFactory.buildMapper(DefaultMapperFactory.java:1372)
at ma.glasnost.orika.impl.DefaultMapperFactory.lookupMapper(DefaultMapperFactory.java:757)
at ma.glasnost.orika.impl.DefaultMapperFactory.lookupMapper(DefaultMapperFactory.java:707)
at ma.glasnost.orika.impl.MapperFacadeImpl.resolveMapper(MapperFacadeImpl.java:591)
at ma.glasnost.orika.impl.MapperFacadeImpl.resolveMappingStrategy(MapperFacadeImpl.java:216)
at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:741)
at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:721)
at com.ctrip.corp.hotelbooking.bookcommon.db.repository.entityMapper.EntityMapper.map(EntityMapper.java:26)
at com.ctrip.corp.hotelbooking.bookcommon.db.repository.impl.CorpOrdersRepositoryImpl.insert(CorpOrdersRepositoryImpl.java:27)
at com.ctrip.corp.hotelbooking.hotelws.manager.createorder.member.sub.SaveHTLCCorpOrdersBiz.saveHTLCCorpOrder(SaveHTLCCorpOrdersBiz.java:95)
at com.ctrip.corp.hotelbooking.hotelws.manager.createorder.member.sub.SaveCorpOrderDBBiz.lambda$saveCorpOrderDBAsync$4(SaveCorpOrderDBBiz.java:92)
at com.ctrip.corp.hotelbooking.bookcommon.utility.util.LambdaUtil.lambda$tryOf$1(LambdaUtil.java:46)
... 6 more
Caused by: java.lang.NullPointerException
at ma.glasnost.orika.impl.generator.JavassistCompilerStrategy.registerClassLoader(JavassistCompilerStrategy.java:133)
at ma.glasnost.orika.impl.generator.JavassistCompilerStrategy.compileClass(JavassistCompilerStrategy.java:235)
at ma.glasnost.orika.impl.generator.SourceCodeContext.compileClass(SourceCodeContext.java:249)
at ma.glasnost.orika.impl.generator.SourceCodeContext.getInstance(SourceCodeContext.java:266)
at ma.glasnost.orika.impl.generator.MapperGenerator.build(MapperGenerator.java:75)
... 18 more
后续通过源码调查发现,是因为使用orika框架映射实体的代码,在jdk1.8---CompletableFuture内部执行,CompletableFuture内部维护的线程池-ForkJoinPool中的Thread,通过方法getContextClassLoader()获取类加载器上下文环境为 NULL
简单解决方案:
为CompletableFuture传入一个自定义的ForkJoinPool,这样线程池中Thread.getContextClassLoader()非空。
深入解决思路
1.tomcat容器类加载机制
2.JDK1.8中CompleteFuture默认的ForkJoinPool线程池,Thread.contextClassLoader如何设置?
3.自定义线程池时,Thread.contextClassLoader如何设置?
3.文章参考
1.NullPointerException in JavassistCompilerStrategy.registerClassLoader when using ForkJoinPool #225
2.Parallel stream doesn't set Thread.contextClassLoader after tomcat upgrade
网友评论