Я использую библиотеку MapStruct для сопоставления объектов, и мне нужно перевести из сущности в dto, но есть проблема, например, в том, что сущность хранит типы животных в виде списка объектов, а dto хранит массив с идентификаторы этих типов. как это можно сделать правильно? Я сделал это, но только вручную, используя циклы. MapStruct для меня что-то новое, поэтому много чего непонятно, надеюсь на вашу помощь, спасибо!
У меня есть этот класс:
@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;
}
И мне нужно это сопоставление Entity с этим 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;
}
Это мои интерфейсы Mapper:
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);
}
Не List<Long>, а массив длинных слов типа long[]
@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());
}
}
Со следующим животным:
Animal(id=1, animalTypes=[AnimalType(id=1), AnimalType(id=2), AnimalType(id=3)])
Сгенерированный ответ, вызвав toDto
AnimalResponse response = AnimalMapper.INSTANCE.toDto(animal);
Будет:
AnimalResponse(id=1, animalTypes=[1, 2, 3])
И еще вопрос, если у меня есть другой массив длинных, таких как long[] VisitLocation, мне нужно использовать @Mapping(source = "visitedLocations", target = "visitedLocations",qualifiedByName = "toArray")?
Массивы берут длинное значение из другого объекта, поэтому нет, вы не можете использовать один и тот же метод. Вам нужно объявить новый с другим именем и использовать его для атрибута «qualifiedByName».
Если вы не хотите использовать Java Reflection
Посещенные локации берутся из одного и того же объекта
Я имею в виду длинные значения, для AnimalTypes длинное значение — это идентификатор AnimalType, а для VisitLocations длинное значение — это идентификатор AnimalLocation. Таким образом, единственный способ повторно использовать метод «toArray» — это реализовать его с помощью Java Reflection или изменить сущности, чтобы расширить класс или реализовать интерфейс с общим геттером, чтобы можно было использовать Java Generics.
Отвечает ли это на ваш вопрос? Преобразование списка объектов в список длинных идентификаторов с помощью Mapstruct