Орика неправильный загрузчик классов используется в случае использования встроенного кота

У нас есть проблема, связанная с загрузчиками классов и orika после перемещения нашего весеннего загрузочного приложения со встроенного причала на встроенный tomcat. Вот два класса:

@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)

После перехода во встроенное отображение кота выдает исключение

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 не может найти все конструкторы аргументов с модификатором доступа по умолчанию (сгенерированным lombok) в SettingsModel.

для упаковки используется баночка.

Я не уверен, если эта проблема связана с Orika или весной загрузки.

Также я обнаружил аналогичную проблему https://gitter.im/spring-projects/spring-boot/archives/2016/01/15 но не уверен, что эта проблема или что-то еще и не может быть применена там, потому что эти классы недоступна в весенней загрузке версии 2.0.3.

Я пытался использовать EclipseJdtCompilerStrategy вместо JavassistCompilerStrategy для Orika, это не помогло

версия весенней загрузки - 2.0.3.

версия orika - 1.5.2

1 ответ

Решение

Проблема, кажется, из-за ограничения в Orika. Он или ваша конфигурация не справляются с ситуацией, когда MapperFacade.map вызывается, когда загрузчик класса контекста потока является потомком загрузчика класса, который загрузил целевой класс. Такое расположение загрузчика классов не относится к Spring Boot. Я полагаю, что та же проблема может возникнуть и в приложении, отличном от Spring Boot, развернутом в Tomcat с целевым классом в Tomcat. shared/lib каталог.

Вы можете обойти ограничение, изменив загрузчик класса контекста потока перед вызовом преобразователя, а затем восстановив его:

@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 ответ.

Другие вопросы по тегам