반응형
Mapstruct를 통해 편하게 응답값을 매핑할 수 있도록 도와주는 라이브러리를 살펴본적 있다. https://wedul.site/703
값을 매핑할 때 필드의 이름이 다를 경우에는 아래 처럼 Mapping애노테이션을 사용해서 source, target에 이름을 명시하여 이를 해결 할 수 있었다.
@Mapping(source = "address", target = "location")
@Mapping(source = "homeTel", target = "homeNumber")
AccountResponse domainToEntity(AccountEntity accountEntity);
하지만 collection을 사용하는 경우 collection 내부의 값의 이름이 다를경우에는 다르게 해결해줘야한다. 예를 들어 AccountEntity에서 AccountResponse로 값을 매핑한다고 가정하였을 때 내부에 images라는 응답값도 매핑한다고 가정해보자. 아래 처럼 AccountImageResponse와 AccountImageEntity 내부에 필드이름이 서로 다를경우 매핑이 정상적으로 되지 않는다. 아래 코드를 살펴보자.
package com.wedul.mapstructtest.dto;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Getter
public class AccountResponse {
private final String name;
private final int age;
private final String location;
private final String homeNumber;
private final List<AccountResponseImage> images;
@Builder
public AccountResponse(String name, int age, String location, String homeNumber, List<AccountResponseImage> images) {
this.name = name;
this.age = age;
this.location = location;
this.homeNumber = homeNumber;
this.images = images;
}
}
package com.wedul.mapstructtest.dto;
import lombok.Builder;
import lombok.Getter;
@Getter
public class AccountResponseImage {
private long id;
private String path;
private String imageName;
@Builder
public AccountResponseImage(long id, String path, String imageName) {
this.id = id;
this.path = path;
this.imageName = imageName;
}
}
package com.wedul.mapstructtest.entity;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Getter
public class AccountEntity {
private String name;
private int age;
private String address;
private String homeTel;
private List<AccountImage> images;
@Builder
public AccountEntity(String name, int age, String address, String homeTel, List<AccountImage> images) {
this.name = name;
this.age = age;
this.address = address;
this.homeTel = homeTel;
this.images = images;
}
}
package com.wedul.mapstructtest.entity;
import lombok.Builder;
import lombok.Getter;
@Getter
public class AccountImage {
private long id;
private String path;
private String name;
@Builder
public AccountImage(long id, String path, String name) {
this.id = id;
this.path = path;
this.name = name;
}
}
두 응답값을 매핑 하는 mapper를 아래처럼 생성하고 비교하는 테스트를 돌려보면 값이 매핑되지 않아 테스트가 실패하는 걸 볼수 있다.
package com.wedul.mapstructtest.mapper;
import com.wedul.mapstructtest.dto.AccountResponse;
import com.wedul.mapstructtest.entity.AccountEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(componentModel = "spring")
public interface AccountMapper {
@Mapping(source = "address", target = "location")
@Mapping(source = "homeTel", target = "homeNumber")
AccountResponse domainToEntity(AccountEntity accountEntity);
}
// 테스트
package com.wedul.mapstructtest;
import com.wedul.mapstructtest.dto.AccountResponse;
import com.wedul.mapstructtest.dto.AccountResponseImage;
import com.wedul.mapstructtest.entity.AccountEntity;
import com.wedul.mapstructtest.entity.AccountImage;
import com.wedul.mapstructtest.mapper.AccountMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class AccountResponseMappingIntegrationTest {
@Autowired
private AccountMapper accountMapper;
@Test
void shouldAccountMappingTest() {
// given
List<AccountImage> imageEntities = List.of(AccountImage.builder()
.id(1L)
.path("path1")
.name("image1")
.build(),
AccountImage.builder()
.id(2L)
.path("path2")
.name("image2")
.build());
AccountEntity accountEntity = AccountEntity.builder()
.age(10)
.name("wedul")
.address("seoul")
.homeTel("02-1111-1111")
.images(imageEntities)
.build();
// when
AccountResponse response = accountMapper.domainToEntity(accountEntity);
// then
AccountResponse expected = AccountResponse.builder()
.age(accountEntity.getAge())
.homeNumber(accountEntity.getHomeTel())
.location(accountEntity.getAddress())
.name(accountEntity.getName())
.images(imageEntities.stream().map(d -> AccountResponseImage.builder()
.path(d.getPath())
.imageName(d.getName())
.id(d.getId())
.build()).collect(Collectors.toList()))
.build();
assertThat(response).usingRecursiveComparison().isEqualTo(expected);
}
}
단순하게 해결해보기 위해 @Mapper value로 아래와 같이 설정해봤으나 없는 property라는 오류를 보게되었다.
@Mapping(source = "images[].name", target = "images[].imageName")
collection내에 필드를 수정할 때는 property를 직접 수정하기 보다는 collection내부에 값을 매핑하기 위한 mapper를 하나더 생성해서 그 mapper를 지정해주면 되는데 @Mapper 애노테이션에서 uses를 사용해서 지정해주면 된다.
// 이미지용 Mapper
package com.wedul.mapstructtest.mapper;
import com.wedul.mapstructtest.dto.AccountResponse;
import com.wedul.mapstructtest.dto.AccountResponseImage;
import com.wedul.mapstructtest.entity.AccountEntity;
import com.wedul.mapstructtest.entity.AccountImage;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(componentModel = "spring")
public interface AccountImageMapper {
@Mapping(source = "name", target = "imageName")
AccountResponseImage domainToEntity(AccountImage accountEntity);
}
// 기존 Mapper에 내부 Collection image매핑을 위한 AccountImageMapper추가
package com.wedul.mapstructtest.mapper;
import com.wedul.mapstructtest.dto.AccountResponse;
import com.wedul.mapstructtest.entity.AccountEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(componentModel = "spring", uses = {
AccountImageMapper.class
})
public interface AccountMapper {
@Mapping(source = "address", target = "location")
@Mapping(source = "homeTel", target = "homeNumber")
AccountResponse domainToEntity(AccountEntity accountEntity);
}
그 다음 테스트를 돌려보면 실패하던 테스트가 성공하는걸 볼 수 있다.
반응형
'web > Spring' 카테고리의 다른 글
spring batch에서 파라미터 시 - 사용 주의 (0) | 2024.05.07 |
---|---|
MapStruct의 mapping방식과 Lobmok 함께 사용 시 값이 mapping되지 않는 이유 (0) | 2023.03.27 |
dynamoDbEnhancedClient range query condition 사용 시 The provided starting key does not match the range key predicate 에러 발생 (0) | 2022.11.05 |
dynamoDbEnhancedClient에서 QueryConditional에서 sort key range 조회하기 (0) | 2022.11.04 |
Dynamodb enhanced client (0) | 2022.07.24 |