Orika ClassCastException в веб-приложении Spring Boot
У меня странное ClassCastException при отображении сущности в DTO с Orika в образце веб-приложения Spring Boot, над которым я работаю. Я получаю исключение, когда пытаюсь выполнить сопоставление развернутого приложения во встроенном Tomcat, но я могу выполнить сопоставление очень хорошо в контексте теста JUnit. Это соответствующие классы (все они очень простые):
JPA лицо:
@Entity
public class Position {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
// getters/setters...
}
DTO:
public class PositionDto {
private Integer id;
private String name;
// getters/setters...
}
Контроллер покоя:
@RestController
public class PositionController {
@Autowired
private PositionService positionService;
@RequestMapping("/position")
public PositionDto get() {
final PositionDto positionDto = positionService.getPosition(1);
return positionDto;
}
}
Класс обслуживания:
@Service
public class PositionServiceImpl implements PositionService {
@Autowired
private PositionRepository positionRepository;
@Autowired
private OrikaBeanMapper mapper;
@Transactional(readOnly = true)
@Override
public PositionDto getPosition(final Position.ID id) {
// This returns a populated Position object with id=1 and name = "Creator"
final Position position = positionRepository.findOne(id.getId());
// This is where the mapping occurs
return mapper.map(position, PositionDto.class);
}
}
Класс OrikaBeanMapper:
@Component
public class OrikaBeanMapper extends ConfigurableMapper implements ApplicationContextAware {
public OrikaBeanMapper() {
super(false);
}
@Override
protected void configureFactoryBuilder(final DefaultMapperFactory.Builder factoryBuilder) {
factoryBuilder.mapNulls(false);
}
// Omitted non-important methods
}
И это трассировка стека ClassCastException:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is ma.glasnost.orika.MappingException: While attempting the following mapping:
sourceClass = class com.dlizarra.startuphub.position.Position
destinationType = com.dlizarra.startuphub.position.PositionDto
resolvedStrategy = InstantiateAndUseCustomMapperStrategy<Position, PositionDto> {customMapper: GeneratedMapper<Position, PositionDto> {usedConverters: [], usedMappers: [], usedMapperFacades: [], usedTypes: [] }, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@73c3e10e, objectFactory: DefaultConstructorObjectFactory<PositionDto>}
Error occurred: java.lang.ClassCastException: com.dlizarra.startuphub.position.Position cannot be cast to com.dlizarra.startuphub.position.Position
-----begin dump of current state-----------------------------
Registered object factories: 1 (approximate size: 110.8 kB)
[PositionDto] : {Position=DefaultConstructorObjectFactory<PositionDto>}
-------------------------------------------------------------------------------
Registered mappers: 1 (approximate size: 17,643.0 kB)
[0] : GeneratedMapper<Position, PositionDto> {usedConverters: [], usedMappers: [], usedMapperFacades: [], usedTypes: [] }
-------------------------------------------------------------------------------
Registered concrete types: 5 (approximate size: 294.3 kB)
[interface java.util.List] : ArrayList<Object>
[interface java.util.Set] : LinkedHashSet<Object>
[interface java.util.Collection] : ArrayList<Object>
[interface java.util.Map] : LinkedHashMap<Object, Object>
[interface java.util.Map$Entry] : MapEntry<Object, Object>
-------------------------------------------------------------------------------
Resolved strategies: 1 (approximate size: 19,850.8 kB)
{source: Position, dest: PositionDto, in-place:false}: InstantiateAndUseCustomMapperStrategy<Position, PositionDto>
{customMapper: GeneratedMapper<Position, PositionDto> {usedConverters: [], usedMappers: [], usedMapperFacades: [], usedTypes: [] }, unenhancer:
ma.glasnost.orika.unenhance.BaseUnenhancer@73c3e10e, objectFactory:
DefaultConstructorObjectFactory<PositionDto>}
-------------------------------------------------------------------------------
Unenhance strategy: ma.glasnost.orika.unenhance.BaseUnenhancer@73c3e10e
-----end dump of current state-------------------------------] with root cause
java.lang.ClassCastException: com.dlizarra.startuphub.position.Position cannot be cast to com.dlizarra.startuphub.position.Position
at ma.glasnost.orika.generated.Orika_PositionDto_Position_Mapper43322711137530$0.mapAtoB(Orika_PositionDto_Position_Mapper43322711137530$0.java) ~[orika-core-1.4.6.jar:na]
at ma.glasnost.orika.impl.mapping.strategy.UseCustomMapperStrategy.map(UseCustomMapperStrategy.java:67) ~[orika-core-1.4.6.jar:na]
at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:742) ~[orika-core-1.4.6.jar:na]
Я действительно понятия не имею, что здесь происходит. Я не понимаю, где он пытается разыграть Позицию в Позицию. Это происходит с каждым классом entity / dto, а не только с Position.
Я могу без проблем сопоставить любой из этих классов, когда я тестирую модулем любой метод, он отлично работает, и все поля отображаются правильно, поэтому я не думаю, что это проблема конфигурации Orika. Исключение возникает только тогда, когда у меня развернуто веб-приложение во встроенном Tomcat, и метод отображения вызывается в методе остальных контроллеров.
Это простое приложение Spring Boot, и это первая конечная точка отдыха, которую я написал в нем. Возможно, я что-то упускаю в конфигурации (у меня есть @EnableAutoConfiguration, так что настраивать не так уж и много), но я не могу догадаться, что заставляет Орику выдавать это исключение.
Будем очень благодарны за любые идеи или намеки на то, что может происходить здесь.
Спасибо!
1 ответ
Я только что понял, что есть обходной путь для этой ошибки, так как несколько месяцев назад уже с Spring Boot 1.4.0 (я полагаю, что это - эта версия), когда они представили возможность настраивать Dev Tools через файл свойств.
Чтобы решить эту проблему, нам просто нужно:
- Создать
META-INF
папка вsrc/main/resources
, - Создайте
spring-devtools.properties
файл в нем. - добавлять
restart.include.orika=/orika-core.*\.jar
в файл.
Как указано в Документах, restart.include
вытянет в загрузчик классов restart любой jar-файл, соответствующий регулярному выражению. Итак, мы включаем orika-core-1.4.6.jar
файл например.