Hankie-2
Hankie-2

Reputation: 5

SpringBoot MapStruct Mapping Entity to DTO with Relationship Entities

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

Upvotes: 0

Views: 5260

Answers (1)

Paul Marcelin Bejan
Paul Marcelin Bejan

Reputation: 1685

@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])

Upvotes: 1

Related Questions