在将我们的spring boot应用程序从嵌入式jetty移动到嵌入式tomcat之后,我们遇到了与类加载器和orika有关的问题。这是两个类:
@Getter
@Builder
public class SettingsModel {
public final Boolean useSelfSignUp;
public final Boolean approve;
public final Boolean verifyData;
public final Boolean collectMid;
public final Boolean flowEnabled;
public final String partnerName;
public final String networkType;
public final String upc;
}
和
@Getter
@Setter
public class SettingsDto {
private Boolean useSelfSignUp;
private Boolean approve;
private Boolean verifyData;
private Boolean collectMid;
private String partnerName;
private String networkType;
private Boolean flowEnabled;
private String upc;
}
和映射代码:
private final MapperFacade mapper;
...
mapper.map(settingsDto, SettingsModel.class)
移动到嵌入式tomcat映射后抛出异常
Caused by: java.lang.IllegalAccessError: tried to access method
onboarding.data.models.SettingsModel.<init>(Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V from class onboarding.data.models.SettingsModel_SettingsDto_ObjectFactory1006013014242721698432955$9
我发现orika使用JavassistCompilerStrategy,它有下一个代码
Class<?> compiledClass = byteCodeClass.toClass(Thread.currentThread().getContextClassLoader(), this.getClass().getProtectionDomain());
当我们使用嵌入式jetty Thread.currentThread()。getContextClassLoader() - 返回sun.misc.Launcher $ AppClassLoader并且所有内容都按预期工作,但在移动到嵌入式tomcat后,它返回TomcatEmbeddedWebappClassLoader并且映射抛出异常。
看起来像两个类加载器工作sun.misc.Launcher $ AppClassLoader和TomcatEmbeddedWebappClassLoader,这个tomcat类加载器无法在SettingsModel中找到所有带有默认访问修饰符(由lombok生成)的args构造函数。
jar包装用于app。
我不确定这个问题是否与Orika或春季靴子有关。
此外,我发现类似的问题https://gitter.im/spring-projects/spring-boot/archives/2016/01/15但不确定是否同样的问题或其他东西,并不能应用修复提供那里,因为该类在春季启动2.0.3.RELEASE版本中不可用。
我尝试使用EclipseJdtCompilerStrategy代替JavassistCompilerStrategy for Orika它没有帮助
spring boot version - 2.0.3.RELEASE
Oriconししおーー1. 5 2
问题似乎是由于Orika的限制。它或者它的配置似乎不能处理当线程上下文类加载器是加载目标类的类加载器的子代时调用MapperFacade.map
的情况。此类加载器安排不是Spring Boot特有的。我相信在Tomcat的shared/lib
目录中使用目标类部署到Tomcat的非Spring Boot应用程序中也会出现同样的问题。
您可以通过在调用映射器之前更改线程上下文类加载器来解决限制,然后再恢复它:
@GetMapping("/test-mapping")
@ResponseStatus(HttpStatus.OK)
public void test() {
SettingsDto settingsDto = new SettingsDto();
ClassLoader previous = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(TestController.class.getClassLoader());
SettingsModel model = mapper.map(settingsDto, SettingsModel.class);
}
finally {
Thread.currentThread().setContextClassLoader(previous);
}
}
随着这一变化,对/test-mapping
的调用产生了200响应。