在我正在研究的示例Spring Boot Web应用程序中,使用Orika将实体映射到DTO时,我遇到了一个奇怪的ClassCastException。当我尝试在嵌入式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...
}

休息 Controller :
@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]

我真的不知道这是怎么回事。我不知道它试图将Position转换为Position的位置。每个实体/dto类都会发生这种情况,而不仅仅是Position。

当我对任何方法进行单元测试时,我都可以毫无问题地映射任何这些类,它可以完美地工作并且所有字段都可以正确地映射,因此我认为这不是Orika配置问题。仅当我将Webapp部署在嵌入式Tomcat中并且在rest Controller 方法中调用了映射方法时,才会发生该异常。

这是一个简单的Spring Boot应用程序,这是我在其中编写的第一个rest端点。也许我在配置中丢失了一些东西(我有@EnableAutoConfiguration,所以配置的东西不多),但是我无法猜测是什么导致Orika抛出此异常。

非常感谢您对这里可能发生的事情有任何想法或暗示。

谢谢!

最佳答案

我刚刚意识到有一个针对此错误的解决方法,因为几个月前,Spring Boot 1.4.0(我相信它是此版本)已经推出了,当时他们引入了通过属性文件自定义Dev Tools的可能性。

要解决此问题,我们只需要:

  • META-INF中创建一个src/main/resources文件夹。
  • 在其中创建spring-devtools.properties文件。
  • restart.include.orika=/orika-core.*\.jar添加到文件中。

  • Docs中所述,restart.include将与Regex匹配的所有jar上载到“重新启动”类加载器中。因此,我们包括了orika-core-1.4.6.jar文件。

    09-28 08:53