I am using the MapStruct library for mapping objects, and I need to translate from an entity to a dto, but there is a problem, for example, that the entity stores animal types as a list of objects, and the dto stores an array with the ids of these types. how can this be done correctly? I did it, but only manually using loops. MapStruct is something new for me, so a lot of things are not clear, I hope for your help, thanks!
I have this class:
@FieldDefaults(level = AccessLevel.PRIVATE)
@Table(name = "animal")
public class Animal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@NotEmpty
@MinCollectionSize
@ElementOfCollectionNotNull
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "animal_types",
joinColumns = {@JoinColumn(name = "animal_id",referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "type_id",referencedColumnName = "id")})
List<AnimalType> animalTypes;
@NotNull
@Min(1)
Float weight;
@NotNull
@Min(1)
Float length;
@NotNull
@Min(1)
Float height;
@NotNull
@NotGender
AnimalGender gender;
AnimalLifeStatus lifeStatus;
TimestampWithTimeZoneJdbcType chippingDateTime;
@NotNull
@ManyToOne
@JoinColumn(name = "chipper_id")
Account chipperId;
@NotNull
@ManyToOne
@JoinColumn(name = "chipping_location_id")
Location chippingLocationId;
@OneToMany(mappedBy = "animal")
List<AnimalLocation> visitedLocations;
TimestampWithTimeZoneJdbcType deathDateTime;
}
And i need this Entity mapping to this DTO:
@FieldDefaults(level = AccessLevel.PRIVATE)
public class AnimalResponse {
Long id;
Long[] animalTypes;
Float weight;
Float length;
Float height;
AnimalGender gender;
AnimalLifeStatus lifeStatus;
TimestampWithTimeZoneJdbcType chippingDateTime;
Integer chippedId;
Long chippingLocationId;
Long[] visitedLocations;
TimestampWithTimeZoneJdbcType deathDateTime;
}
This is my Mapper Interfaces:
public interface BaseMapper<ENTITY, DTO> {
DTO toDto(ENTITY entity);
ENTITY toEntity(DTO dto);
List<DTO> toDtoList(List<ENTITY> entityList);
List<ENTITY> toEntityList(List<DTO> dtoList);
}
@Mapper
public interface AnimalMapper extends BaseMapper<Animal, AnimalResponse> {
AnimalMapper INSTANCE = Mappers.getMapper(AnimalMapper.class);
}
@Mapper
public interface AnimalMapper extends BaseMapper<Animal, AnimalResponse> {
AnimalMapper INSTANCE = Mappers.getMapper(AnimalMapper.class);
@Override
@Named("toDto")
@Mapping(source = "animalTypes", target = "animalTypes", qualifiedByName = "toArray")
AnimalResponse toDto(Animal entity);
@Override
@IterableMapping(qualifiedByName = "toDto")
List<AnimalResponse> toDtoList(List<Animal> entityList);
@Override
@Named("toEntity")
@Mapping(source = "animalTypes", target = "animalTypes", qualifiedByName = "toArrayList")
Animal toEntity(AnimalResponse dto);
@IterableMapping(qualifiedByName = "toEntity")
List<Animal> toEntityList(List<AnimalResponse> dtoList);
@Named("toArray")
default Long[] toArray(List<AnimalType> animalTypes) {
return animalTypes.stream()
.map(AnimalType::getId)
.toArray(size -> new Long[size]);
}
@Named("toArrayList")
default List<AnimalType> toArrayList(Long[] animalTypes) {
return Arrays.stream(animalTypes)
.map(AnimalType::new) // new object just for example purposes, you can instead call the repository findById
.collect(Collectors.toList());
}
}
With the following animal:
Animal(id=1, animalTypes=[AnimalType(id=1), AnimalType(id=2), AnimalType(id=3)])
the generated response by calling toDto
AnimalResponse response = AnimalMapper.INSTANCE.toDto(animal);
will be:
AnimalResponse(id=1, animalTypes=[1, 2, 3])