Orika 在使用嵌入式时使用了错误的类加载器 tomcat

Orika wrong classloader used in case of using Embedded tomcat

在将我们的 spring 引导应用程序从嵌入式码头移动到嵌入式 tomcat 后,我们遇到了与 class 加载程序和 orika 相关的问题。 这里有两个 classes:

@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

我发现 orika 使用 JavassistCompilerStrategy,它有下一个代码

Class<?> compiledClass = byteCodeClass.toClass(Thread.currentThread().getContextClassLoader(), this.getClass().getProtectionDomain());

当我们使用嵌入式码头时 Thread.currentThread().getContextClassLoader() - returns sun.misc.Launcher$AppClassLoader 一切都按预期工作,但在移动到嵌入式后 tomcat它 returns TomcatEmbeddedWebappClassLoader 和映射抛出异常。

看起来有两个 class 加载器在工作 sun.misc.Launcher$AppClassLoader 和 TomcatEmbeddedWebappClassLoader 并且这个 tomcat classloader 找不到所有带有默认访问修饰符的参数构造器(生成通过 lombok)在 SettingsModel.

应用程序使用jar包装。

我不确定这个问题是否与 Orika 或 spring 引导有关。

我也发现了类似的问题 https://gitter.im/spring-projects/spring-boot/archives/2016/01/15 但不确定是否是同样的问题或其他问题,并且无法应用那里提供的修复,因为 class 在 spring 中不可用开机 2.0.3.RELEASE 版本.

我尝试为 Orika 使用 EclipseJdtCompilerStrategy 而不是 JavassistCompilerStrategy 但没有帮助

spring 引导版本 - 2.0.3.RELEASE

orika 版本 - 1.5.2

问题似乎是由于 Orika 的限制。它或您的配置似乎无法处理当线程上下文 class 加载器是加载目标 class 加载器的子级时调用 MapperFacade.map 的情况20=]。此 class 加载程序安排并非特定于 Spring Boot。我相信同样的问题也会发生在部署到 Tomcat 的非 Spring 引导应用程序中,目标 class 在 Tomcat 的 shared/lib 目录中。

您可以通过在调用映射器之前更改线程上下文 class 加载程序并随后恢复它来解决此限制:

@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 响应。