Orika错误的类加载器在使用嵌入式tomcat的情况下使用

时间:2018-09-13 20:53:46

标签: java spring-boot classloader embedded-tomcat-8 orika

在将我们的Spring Boot应用程序从嵌入式码头转移到嵌入式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());

当我们使用嵌入式码头Thread.currentThread()。getContextClassLoader()-返回sun.misc.Launcher $ AppClassLoader时,一切都按预期工作,但是移到嵌入式tomcat后,它返回TomcatEmbeddedWebappClassLoader,并且映射引发异常。

就像两个类加载器一样,它们都在工作sun.misc.Launcher $ AppClassLoader和TomcatEmbeddedWebappClassLoader,而这个tomcat类加载器在SettingsModel中找不到具有默认访问修饰符(由lombok生成)的所有args构造函数。

jar包装用于应用程序。

我不确定此问题是否与Orika或Spring Boot有关。

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

对于Orika,我尝试使用EclipseJdtCompilerStrategy而不是JavassistCompilerStrategy来解决问题

spring boot版本-2.0.3.RELEASE

orika版本-1.5.2

1 个答案:

答案 0 :(得分:1)

该问题似乎是由于Orika中的限制所致。当线程上下文类加载器是加载目标类的类加载器的子代时,它或您的配置似乎无法处理调用MapperFacade.map的情况。这种类加载器的安排并不特定于Spring Boot。我相信在目标目录位于Tomcat的shared/lib目录中的非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响应。