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);