Home > database >  MapStruct. Map from List<Integer> to List<Object>
MapStruct. Map from List<Integer> to List<Object>

Time:10-11

Source

sourceDto {
 List<Integer> ids;
}

Target

targetDto {
 List<CustomObject> myObjects;
}

Custom Object

CustomObject {
 Integer id,
 String name,
 String slug
}

Note I am using an external API that always need name and slug initialised to an empty string. I mean, sending only the ID will no work. That's why I am trying so with Mapper

CodePudding user response:

I would probably define a custom mapping function for this.

In your MapStruct interface file, you can add default functions. These functions can be used to create more advanced MapStruct behaviour.

Example:

/**
 * Map a {@link SourceDto} to a {@link TargetDto} instance
 * <br/>
 * Names and slugs will be set to empty strings by default
 * Null values will be ignored
 *
 * @param sourceDto Source input
 * @return Target output mapped from the source input
 */
default TargetDto sourceToTargetDto(final SourceDto sourceDto) {
    // Protect against nulls / empty lists
    if (sourceDto == null || sourceDto.getIds() == null || sourceDto.getIds().isEmpty()) {
        return null;
    }

    // Map source to target while respecting the new empty string requirement
    final var targetDto = new TargetDto();
    targetDto.setMyObjects(sourceDto
            .getIds()
            .stream()
            .filter(Objects::nonNull)
            .map(id -> new CustomObject(id, "", ""))
            .collect(Collectors.toList()));

    return targetDto;
}

Cheers,

-T

CodePudding user response:

Create all objects and their constructors. you can do it with annotations.

I have created one more constructor for this case that name and slug are empty string.

/**
 * The type Source dto.
 */
@AllArgsConstructor
@Data
@NoArgsConstructor
class SourceDto {
    /**
     * The Ids.
     */
    private List<Integer> ids;
}

/**
 * The type Custom object.
 */
@AllArgsConstructor
@Data
@NoArgsConstructor
class CustomObject {
    /**
     * The Id.
     */
   private Integer id;
    /**
     * The Name.
     */
   private String name;
    /**
     * The Slug.
     */
   private String slug;

    /**
     * Instantiates a new Custom object.
     *
     * @param id the id
     */
    public CustomObject(Integer id) {
        this.id = id;
        this.name = Strings.EMPTY;
        this.slug = Strings.EMPTY;
    }
}

/**
 * The type Target dto.
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
class TargetDto {
    /**
     * The My objects.
     */
   private List<CustomObject> myObjects;
}

/**
 * The type SourceDtoToTargetDtoConverter.
 */
@Component
class SourceDtoToTargetDtoConverter implements Converter<SourceDto,TargetDto> {

    @Override
    public TargetDto convert(SourceDto source) {
        return TargetDto.builder()
                .myObjects(Optional.ofNullable(source.getIds().stream()
                        .map(CustomObject::new)
                        .collect(Collectors.toList()))
                        .orElse(new ArrayList<>()))
                .build(); 
                
    }
}

CodePudding user response:

Create all-argument constructor in CustomObject

class CustomObject {
    Integer id;
    String name;
    String slug;

    public CustomObject(Integer id, String name, String slug) {
        this.id = id;
        this.name = name;
        this.slug = slug;
    }
}

Then you can create List<CustomObject> as follows,

List<CustomObject> myObjects = sourceDto.getIds()
                .stream()
                .map(id -> new CustomObject(id, Strings.EMPTY, Strings.EMPTY))
                .collection(Collectors.toList());
class TargetDto {
    List<CustomObject> myObjects;

    public TargetDto() {}

    public TargetDto(List<CustomObject> myObjects) {
        this.myObjects = myObjects;
    }
}
TargetDto targetDto = new TargetDto(myObjects);
  • Related