javamapstruct

I want to give condition to list.add in the ~impl file generated by mapstruct. What should I do?


I wonder if it is possible to apply a conditional expression when converting an entity to dto using mapstruct. There are many search results for property, but I can't find it when I'm curious.

In the example code below, in the StudentMenuMapperImpl.java file list.add( toDto( studentMenu ) ) I want to give conditional expression to

I know how to override toDto in StudentMenuMapper Interface. But I want to know another simple way. (like annotation)

Alternatively, is it possible to return null from the toDto function with @AfterMapping and @BeforeMapping?

[StudentMenuDto.java]

public class StudentMenuDto {
    private Long id;
    private Long parentId;
    List<StudentMenuDto> childStudentMenuList;
}

[GenericMapper.java]

public interface GenericMapper<D, E> {
    D toDto(E entity);
    List<D> toDto(List<E> entityList);
}

[StudentMenuMapper.java]

@Mapper
public interface StudentMenuMapper extends GenericMapper<StudentMenuDto, StudentMenu> {
    StudentMenuMapper INSTANCE = Mappers.getMapper(StudentMenuMapper.class);
    
    @Override
    StudentMenuDto toDto(StudentMenu entity);
}

[StudentMenuMapperImpl.java] - impl file genereated by mapstruct

@Component
public class StudentMenuMapperImpl implements StudentMenuMapper {

    @Override
    public List<StudentMenuDto> toDto(List<StudentMenu> entityList) {
        if ( entityList == null ) {
            return null;
        }

        List<StudentMenuDto> list = new ArrayList<StudentMenuDto>( entityList.size() );
        for ( StudentMenu studentMenu : entityList ) {
            /* [AS-IS] */
            list.add( toDto( studentMenu ) );
            /* [TO-BE] I want to add various conditional statements like this
                if(studentMenu.getId != 1){
                    list.add( toDto( studentMenu ) );
                }
            */
        }

        return list;
    }

    @Override
    public StudentMenuDto toDto(StudentMenu entity) {

        if ( entity == null ) {
            return null;
        }

        StudentMenuDto studentMenuDto = new StudentMenuDto();

        studentMenuDto.setId( entity.getId() );
        studentMenuDto.setParentId( entityParentStudentMenuId( entity ) );
        studentMenuDto.setChildStudentMenuList( toDto( entity.getChildStudentMenuList() ) );

        return studentMenuDto;
    }

    private Long entityParentStudentMenuId(StudentMenu studentMenu) {
        if ( studentMenu == null ) {
            return null;
        }
        StudentMenu parentStudentMenu = studentMenu.getParentStudentMenu();
        if ( parentStudentMenu == null ) {
            return null;
        }
        Long id = parentStudentMenu.getId();
        if ( id == null ) {
            return null;
        }
        return id;
    }
}

Solution

  • They are working on this type of filter, which will be released with version 1.6.0
    You can follow the request on github: Allow conditions/filters mapping iterables and maps

    At the moment the solution is to create a method annoted with @AfterMapping which simply remove useless object from the list.

      @AfterMapping
      default void removeNullItem(
          @MappingTarget List<Target> listTarget
      ) {
        listTarget.removeIf(Objects::isNull);
      }
    

    If you need, you can take a look to: After-Mapping Annotations