Search code examples
javamavenmapstructannotation-processingmapper

Mapstruct uses not working, how to make mapstruct "uses" use other mapper for inner fields


Mapstruct "uses" not working, it maps all entities in one mapper, instead of using different mappers for different entities I have pom

`<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${compiler.version}</version>
            <configuration>
                <source>17</source>
                <target>17</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>${lombok.version}</version>
                    </path>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${mapstruct.version}</version>
                    </path>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok-mapstruct-binding</artifactId>
                        <version>0.2.0</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>`
@Mapper(uses = {ParticipantMapper.class})
public interface RoomMapper {

    RoomMapper INSTANCE = Mappers.getMapper(RoomMapper.class);

    @Mapping(target = "participant", source = "participant")
    RoomFullDto entityToData(RoomEntity entity);

    @Mapping(target = "participant", source = "participant")
    RoomEntity dataToEntity(RoomFullDto entity);

    @Named("EntityToShortData")
    RoomShortDto entityToShortData(RoomEntity entity);

    @Named("DataToEntity")
    RoomEntity shortDataToEntity(RoomShortDto entity);
}

and

@Mapper
public interface ParticipantMapper {


    ParticipantMapper INSTANCE = Mappers.getMapper(ParticipantMapper.class);

    @Named("DataToEntity")
    @Mapping(target = "room.id", source = "roomId")
    @Mapping(target = "user.id", source = "userId")
    @Mapping(target = "nicknameInRoom", source = "username")
    ParticipantEntity dtoToEntity (ParticipantDto participantDto);

    @Named("EntityToData")
    @Mapping(target = "roomId", source = "room.id")
    @Mapping(target = "userId", source = "user.id")
    @Mapping(target = "username", source = "nicknameInRoom")
    ParticipantDto entityToDto (ParticipantEntity participantDto);
}

in RoomMapperImpl mapstruct generate without using ParticipantMapper, so i cant't configure how to map fields and it ignores some fields

public RoomFullDto entityToData(RoomEntity entity) {
        if ( entity == null ) {
            return null;
        }

        RoomFullDto roomFullDto = new RoomFullDto();

        roomFullDto.setParticipant( participantEntitySetToParticipantDtoList( entity.getParticipant() ) );
        roomFullDto.setId( entity.getId() );
        roomFullDto.setName( entity.getName() );

        return roomFullDto;
    }

protected List<ParticipantDto> participantEntitySetToParticipantDtoList(Set<ParticipantEntity> set) {
        if ( set == null ) {
            return null;
        }

        List<ParticipantDto> list = new ArrayList<ParticipantDto>( set.size() );
        for ( ParticipantEntity participantEntity : set ) {
            list.add( participantEntityToParticipantDto( participantEntity ) );
        }

        return list;
    }

ParticipantDto participantEntityToParticipantDto(ParticipantEntity participantEntity) {
        if ( participantEntity == null ) {
            return null;
        }

        ParticipantDto participantDto = new ParticipantDto();

        participantDto.setId( participantEntity.getId() );
        participantDto.setIsBanned( participantEntity.getIsBanned() );
        if ( participantEntity.getRole() != null ) {
            participantDto.setRole( participantEntity.getRole().name() );
        }

        return participantDto;
    }

I tried to configure different versions of dependencies and annotationProcessors, it dont works


Solution

  • The RoomFullDto#participant field type is java.util.List<ParticipantDto> (not ParticipantDto)

    The ParticipantEntity#participant field type is java.util.Set<ParticipantEntity> (not ParticipantEntity)

    We need to declare the mapping process between two different types: Set<ParticipantEntity> and List<ParticipantDto>

    1. Set<ParticipantEntity> -> List<ParticipantDto> transformation
    2. List<ParticipantDto> -> Set<ParticipantEntity> transformation

    Please try to add 2 more methods for ParticipantMapper.java:

    Create a new method ParticipantMapper#mapToList:

    @Mapper
    public interface ParticipantMapper {
      
    
        ParticipantMapper INSTANCE = Mappers.getMapper(ParticipantMapper.class);
    
        @Named("DataToEntity")
        @Mapping(target = "room.id", source = "roomId")
        @Mapping(target = "user.id", source = "userId")
        @Mapping(target = "nicknameInRoom", source = "username")
        ParticipantEntity dtoToEntity (ParticipantDto participantDto);
    
        @Named("EntityToData")
        @Mapping(target = "roomId", source = "room.id")
        @Mapping(target = "userId", source = "user.id")
        @Mapping(target = "username", source = "nicknameInRoom")
        ParticipantDto entityToDto (ParticipantEntity participantDto);
      
    
        //+ 2 additional mapping methods without any annota
        List<ParticipantDto> mapToDtoList(Set<ParticipantEntity> set);
    
        Set<ParticipantEntity> mapToEntitySet(List<ParticipantDto> list);
    }
    

    MapStruct Documentation: 6. Mapping collections