티스토리 뷰
728x90
반응형
Mapstruct를 통해 객체 매핑 작업을 할 때 필드명은 같지만 타입이 다를 때 타입변환이 자동으로 되는데
String -> int 필드로 변환할 때는 주의해야한다.
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
public class WishListDto {
private Integer index;
private String title;
private String category;
private String address;
private String roadAddress;
private String homePageLink;
private String imageLink;
private boolean isVisit;
private int visitCount;
private LocalDateTime lastVisitDate;
private String sameFieldName; //타입은 다르고 변수명은 동일한 필드
}
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
@Table(name = "WishList")
@SequenceGenerator(name="RES_SEQ_GEN", sequenceName = "RES_SEQ", initialValue = 1, allocationSize = 1)
public class WishListEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "RES_SEQ_GEN")
private Integer index;
private String title;
private String category;
private String address;
private String roadAddress;
private String homePageLink;
private String imageLink;
private boolean isVisit;
private int visitCount;
@UpdateTimestamp
private LocalDateTime lastVisitDate;
private int sameFieldName; //타입은 다르고 변수명은 동일한 필드
}
Mapper Interface
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface WishListMapper extends EntityMapper<WishListDto, WishListEntity> {
WishListMapper INSTANCE = Mappers.getMapper(WishListMapper.class);
WishListDto toDto(WishListEntity wishListEntity);
WishListEntity toEntity(WishListDto wishListDto);
}
Compile된 Mapper 구현체
public class WishListMapperImpl implements WishListMapper {
@Override
public WishListDto toDto(WishListEntity wishListEntity) {
if ( wishListEntity == null ) {
return null;
}
WishListDto.WishListDtoBuilder<?, ?> wishListDto = WishListDto.builder();
wishListDto.index( wishListEntity.getIndex() );
wishListDto.title( wishListEntity.getTitle() );
wishListDto.category( wishListEntity.getCategory() );
wishListDto.address( wishListEntity.getAddress() );
wishListDto.roadAddress( wishListEntity.getRoadAddress() );
wishListDto.homePageLink( wishListEntity.getHomePageLink() );
wishListDto.imageLink( wishListEntity.getImageLink() );
wishListDto.visitCount( wishListEntity.getVisitCount() );
wishListDto.lastVisitDate( wishListEntity.getLastVisitDate() );
wishListDto.sameFieldName( String.valueOf( wishListEntity.getSameFieldName() ) ); //필드 타입이 다를 때 형변환
return wishListDto.build();
}
@Override
public WishListEntity toEntity(WishListDto wishListDto) {
if ( wishListDto == null ) {
return null;
}
WishListEntity wishListEntity = new WishListEntity();
wishListEntity.setIndex( wishListDto.getIndex() );
wishListEntity.setTitle( wishListDto.getTitle() );
wishListEntity.setCategory( wishListDto.getCategory() );
wishListEntity.setAddress( wishListDto.getAddress() );
wishListEntity.setRoadAddress( wishListDto.getRoadAddress() );
wishListEntity.setHomePageLink( wishListDto.getHomePageLink() );
wishListEntity.setImageLink( wishListDto.getImageLink() );
wishListEntity.setVisit( wishListDto.isVisit() );
wishListEntity.setVisitCount( wishListDto.getVisitCount() );
wishListEntity.setLastVisitDate( wishListDto.getLastVisitDate() );
if ( wishListDto.getSameFieldName() != null ) {
wishListEntity.setSameFieldName( Integer.parseInt( wishListDto.getSameFieldName() ) ); //필드 타입이 다를 때 형변환
}
return wishListEntity;
}
}
String 변수를 null 체크는 하지만 "" 공란일 때는 체크하지 않고 Integer.parseInt()를 타게 되면 NumberFormatException 발생된다.
class WishListDtoTest {
@Test
void testMapToDto_whenStringFieldIsNotEmpty() {
WishListDto dto = WishListDto.builder()
.index(1)
.title("title")
.address("address")
.sameFieldName("0") // String 필드에 "0"
.build();
WishListEntity entity = WishListMapper.INSTANCE.toEntity(dto);
assertThat(entity.getSameFieldName()).isEqualTo(0);
}
@Test
void testMapToDto_whenStringFieldIsNull() {
WishListDto dto = WishListDto.builder()
.index(1)
.title("title")
.address("address")
.sameFieldName(null) // String 필드에 null
.build();
WishListEntity entity = WishListMapper.INSTANCE.toEntity(dto);
assertThat(entity.getSameFieldName()).isEqualTo(0);
}
@Test
void testMapToDto_whenStringFieldIsEmpty() {
WishListDto dto = WishListDto.builder()
.index(1)
.title("title")
.address("address")
.sameFieldName("") // String 필드에 공란
.build();
assertThatThrownBy(() -> {
WishListEntity entity = WishListMapper.INSTANCE.toEntity(dto); //Mapstruct 객체 매핑 시 NumberFormatException
}).isInstanceOf(NumberFormatException.class);
}
}
Mapstruct mapper interface에서 String -> int 형변환을 qualifiedByName을 사용해 명시적으로 선언
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface WishListMapper extends EntityMapper<WishListDto, WishListEntity> {
WishListMapper INSTANCE = Mappers.getMapper(WishListMapper.class);
WishListDto toDto(WishListEntity wishListEntity);
@Mapping(target = "sameFieldName", source = "sameFieldName", qualifiedByName = "mapToInteger")
WishListEntity toEntity(WishListDto wishListDto);
@Named("mapToInteger")
default int mapToInteger(String str) {
if (str == null || str.isEmpty()) {
return 0;
}
return Integer.parseInt(str);
}
}
Compile된 Mapper 구현체
public class WishListMapperImpl implements WishListMapper {
@Override
public WishListDto toDto(WishListEntity wishListEntity) {
if ( wishListEntity == null ) {
return null;
}
WishListDto.WishListDtoBuilder<?, ?> wishListDto = WishListDto.builder();
wishListDto.index( wishListEntity.getIndex() );
wishListDto.title( wishListEntity.getTitle() );
wishListDto.category( wishListEntity.getCategory() );
wishListDto.address( wishListEntity.getAddress() );
wishListDto.roadAddress( wishListEntity.getRoadAddress() );
wishListDto.homePageLink( wishListEntity.getHomePageLink() );
wishListDto.imageLink( wishListEntity.getImageLink() );
wishListDto.visitCount( wishListEntity.getVisitCount() );
wishListDto.lastVisitDate( wishListEntity.getLastVisitDate() );
wishListDto.sameFieldName( String.valueOf( wishListEntity.getSameFieldName() ) );
return wishListDto.build();
}
@Override
public WishListEntity toEntity(WishListDto wishListDto) {
if ( wishListDto == null ) {
return null;
}
WishListEntity wishListEntity = new WishListEntity();
wishListEntity.setSameFieldName( mapToInteger( wishListDto.getSameFieldName() ) );
wishListEntity.setIndex( wishListDto.getIndex() );
wishListEntity.setTitle( wishListDto.getTitle() );
wishListEntity.setCategory( wishListDto.getCategory() );
wishListEntity.setAddress( wishListDto.getAddress() );
wishListEntity.setRoadAddress( wishListDto.getRoadAddress() );
wishListEntity.setHomePageLink( wishListDto.getHomePageLink() );
wishListEntity.setImageLink( wishListDto.getImageLink() );
wishListEntity.setVisit( wishListDto.isVisit() );
wishListEntity.setVisitCount( wishListDto.getVisitCount() );
wishListEntity.setLastVisitDate( wishListDto.getLastVisitDate() );
return wishListEntity;
}
}
"" 공란일 때도 0으로 정상 변환
@Test
void testMapToDto_whenStringFieldIsEmpty() {
WishListDto dto = WishListDto.builder()
.index(1)
.title("title")
.address("address")
.sameFieldName("") // String 필드에 공란
.build();
WishListEntity entity = WishListMapper.INSTANCE.toEntity(dto);
assertThat(entity.getSameFieldName()).isEqualTo(0);
}
https://mapstruct.org/documentation/stable/reference/html/#selection-based-on-qualifiers
MapStruct 1.5.5.Final Reference Guide
If set to true, MapStruct in which MapStruct logs its major decisions. Note, at the moment of writing in Maven, also showWarnings needs to be added due to a problem in the maven-compiler-plugin configuration.
mapstruct.org
728x90
반응형
'Java' 카테고리의 다른 글
[Java] 단위테스트 Spock Framework (0) | 2024.06.09 |
---|---|
[Java] Mockito BDD (Behavior Driven Development) (0) | 2024.06.02 |
[Java] Mapstruct 사용 시 @Builder 패턴 객체 주의 사항 (0) | 2024.04.15 |
[Java] Mustache Template Rendering (0) | 2024.04.03 |
[Java] Object Mapping Frameworks 성능 비교 (0) | 2024.04.02 |
반응형
300x250