Skip to content

Inconsistent ambiguous mapping method error: generic vs raw types #3668

@dsubelman

Description

@dsubelman

Expected behavior

It should compile or fail with ambiguous mapping method error in both cases (generic vs raw type).

Actual behavior

It fails for generic type case but not for raw type.

Steps to reproduce the problem

Child:

public abstract class Child {

    private Long id;

    // Getters and setters...

}

public class ChildA extends Child { }

public class ChildB extends Child { }

Parent:

public abstract class Parent<T extends Child> {

    private Long id;

    private T child;

    // Getters and setters...

}

public class ParentA extends Parent<ChildA> { }

public class ParentB extends Parent<ChildB> { }

ChildDto:

public abstract class ChildDto {

    private Long id;

    // Getters and setters...

}

public class ChildDtoA extends ChildDto { }

public class ChildDtoB extends ChildDto { }

ParentDto:

public class ParentDto<T extends ChildDto> {

    private Long id;

    private T child;

    // Getters and setters...

}

public class ParentDtoA extends ParentDto<ChildDtoA> { }

public class ParentDtoB extends ParentDto<ChildDtoB> { }

Child mapper:

@Mapper(subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION)
public interface ChildMapper {

    @SubclassMapping( target = ChildA.class, source = ChildDtoA.class )
    @SubclassMapping( target = ChildB.class, source = ChildDtoB.class )
    Child toEntity(ChildDto childDto);

    @SubclassMapping( target = ChildDtoA.class, source = ChildA.class )
    @SubclassMapping( target = ChildDtoB.class, source = ChildB.class )
    ChildDto toDto(Child child);

    ChildA toEntity(ChildDtoA childDto);

    ChildDtoA toDto(ChildA child);

    ChildB toEntity(ChildDtoB childDto);

    ChildDtoB toDto(ChildB child);

}

Parent mapper :

Case 1 (generic type):

@Mapper(uses = { ChildMapper.class }, subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION )
public interface ParentMapper {

    @SubclassMapping( target = ParentA.class, source = ParentDtoA.class )
    @SubclassMapping( target = ParentB.class, source = ParentDtoB.class )
    Parent<?> toEntity(ParentDto<?> parentDto);

    @SubclassMapping( target = ParentDtoA.class, source = ParentA.class )
    @SubclassMapping( target = ParentDtoB.class, source = ParentB.class )
    ParentDto<?> toDto(Parent<?> parent);

    ParentA toEntity(ParentDtoA parentDto);

    ParentDtoA toDto(ParentA parent);

    ParentB toEntity(ParentDtoB parentDto);

    ParentDtoB toDto(ParentB parent);

}

❌ Fails with errors:

[ERROR] ParentMapper.java: Ambiguous mapping methods found for mapping property "? child" to ?: Child ChildMapper.toEntity(ChildDto childDto), ChildA ChildMapper.toEntity(ChildDtoA childDto), ChildB ChildMapper.toEntity(ChildDtoB childDto). See https://mapstruct.org/faq/#ambiguous for more info.
[ERROR] ParentMapper.java: Ambiguous mapping methods found for mapping property "? child" to ?: ChildDto ChildMapper.toDto(Child child), ChildDtoA ChildMapper.toDto(ChildA child), ChildDtoB ChildMapper.toDto(ChildB child). See https://mapstruct.org/faq/#ambiguous for more info.

Case 2 (raw type):

@Mapper(uses = { ChildMapper.class }, subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION )
public interface ParentMapper {

    @SubclassMapping( target = ParentA.class, source = ParentDtoA.class )
    @SubclassMapping( target = ParentB.class, source = ParentDtoB.class )
    Parent toEntity(ParentDto parentDto);

    @SubclassMapping( target = ParentDtoA.class, source = ParentA.class )
    @SubclassMapping( target = ParentDtoB.class, source = ParentB.class )
    ParentDto toDto(Parent parent);

    ParentA toEntity(ParentDtoA parentDto);

    ParentDtoA toDto(ParentA parent);

    ParentB toEntity(ParentDtoB parentDto);

    ParentDtoB toDto(ParentB parent);

}

✔️ When removing <?> it does not fail.

MapStruct Version

MapStruct 1.6.0

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions