2015-10-25 10 views
6

Ich habe eine seltsame ClassCastException beim Zuordnen einer Entität zu einem DTO mit Orika in einer Beispiel-Spring Boot-Webapp ich arbeite an. Ich erhalte die Ausnahme, wenn ich versuche, das Mapping auf der implementierten App im eingebetteten Tomcat durchzuführen, aber ich kann das Mapping in einem JUnit-Testkontext gut machen. Dies sind die entsprechenden Klassen (sie alle sind sehr einfach):Orika ClassCastException im Frühjahr Boot webapp

JPA-Entität:

@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... 
} 

Ruhe Controller:

@RestController 
public class PositionController { 

    @Autowired 
    private PositionService positionService; 

    @RequestMapping("/position") 
    public PositionDto get() { 
     final PositionDto positionDto = positionService.getPosition(1); 
     return positionDto; 
    } 
} 

Service-Klasse:

@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 Klasse:

@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 

} 

Und das ist die Stacktrace des Classcast:

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: [email protected], 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: 
[email protected], objectFactory: 
DefaultConstructorObjectFactory<PositionDto>} 
------------------------------------------------------------------------------- 
Unenhance strategy: [email protected] 
-----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] 

ich wirklich keine Ahnung, was hier los ist. Ich bekomme nicht, wo es Position in Position zu werfen versucht. Dies geschieht bei jeder Entity/Dto-Klasse, nicht nur bei Position.

Ich kann jede dieser Klassen ohne Probleme zuordnen, wenn ich Unit-Tests jede Methode, es funktioniert perfekt und alle Felder korrekt zugeordnet werden, so glaube ich nicht, es ist ein Orika-Konfigurationsproblem. Die Ausnahme tritt nur auf, wenn ich die Webanwendung im eingebetteten Tomcat bereitgestellt habe und die Mapping-Methode innerhalb der Rest-Controller-Methode aufgerufen wird.

Es ist eine einfache Spring Boot-Anwendung und das ist der erste Rest Endpunkt, den ich darin geschrieben habe. Vielleicht fehlt mir etwas in der Konfiguration (ich habe @EnableAutoConfiguration, also gibt es nicht so viel zu konfigurieren), aber ich kann nicht erraten, was Orika diese Ausnahme verursacht.

Irgendwelche Ideen oder Hinweise darüber, was hier geschehen könnte, würden sehr geschätzt werden.

Danke!

+4

Verwenden Sie Spring Boot Dev Tools?Es klingt, als würdest du [dieses bekannte Problem] treffen (https://github.com/spring-projects/spring-boot/issues/3697). –

+0

Wow das war ein harter, danke Andy. Ja, ich verwende Dev Tools, Orika 1.4.6 und Boot 1.3.0 M5. Jetzt verstehe ich, dass die ClassCastException von Position zu Position von jeder Klasse verursacht wurde, die von einem anderen Klassenlader geladen wurde. Ich kann sehen, dass ihr an einer Lösung arbeitet, da sie nicht nur bei Orika auftritt und die Orika-Jungs auch das Problem angehen und es könnte für 1.5 behoben werden. –

+0

@AndyWilkinson und David Ich könnte dir jetzt einen großen Mann küssen. Ich bin mir nicht sicher, wie viele Stunden ich damit verbracht habe ... aber ich schaudere beim Nachdenken. Mapping funktionierte perfekt in Unit Tests keine Würfel in dev/Live-Lauf. Ich jagte alle möglichen anderen roten Heringe, bis ich auf diesen Posten stolperte. Prost – wired00

Antwort

4

Ich habe gerade festgestellt, es gibt eine Abhilfe für diesen Fehler seit ein paar Monaten bereits mit Spring Boot 1.4.0 (ich glaube, es ist diese Version), als sie die Möglichkeit, Dev Tools über eine Eigenschaftendatei anpassen.

Um dieses Problem zu lösen, die wir gerade haben:

  1. einen META-INF Ordner in src/main/resources erstellen.
  2. Erstellen Sie spring-devtools.properties Datei darin.
  3. Fügen Sie der Datei restart.include.orika=/orika-core.*\.jar hinzu.

Wie in der Docs angegeben, wird der restart.include ziehen in den ‚Neustart‘ Classloader sich jede jar die Regex übereinstimmen. So fügen wir beispielsweise die Datei orika-core-1.4.6.jar ein.

+0

Dies funktionierte perfekt für mich, denn nach dem Github-Problem können die Orika-Jungs das hoffentlich beheben. Befolgen Sie diese Schritte genau starten Sie Ihre Anwendung> glückliche Tage neu. – wired00