Java 객체 간의 매핑을 도와주는 라이브러리인 MapStruct에 대해 알아보자.
MapStruct
MapStruct는 Java Bean 유형 간의 매핑 구현을 단순화해주는 라이브러리로써 다음과 같은 장점을 가지고 있다.
- 컴파일 시점에 코드를 생성하여 런타임 안정성 보장
- 다른 매핑 라이브러리보다 빠르다
- 어노테이션을 사용한 선언적 개발로 구현이 쉽다
MapStruct 의존성 추가
implementation("org.mapstruct:mapstruct:1.5.3.Final")
annotationProcessor("org.mapstruct:mapstruct-processor:1.5.3.Final")
Mapper 인터페이스 구성
componentModel = "spring"
- Spring 컨테이너에 Bean 등록
unmappedTargetPolicy
ReportingPolicy.IGNORE - Target에 매핑되지 않는 필드 무시
ReportingPolicy.ERROR - Target에 매핑되지 않는 필드 ERROR 발생
ReportingPolicy.WARN - Target에 매핑되지 않는 필드 WARN 발생
nullValueMappingStrategy, nullValueIterableMappingStrategy
NullValueMappingStrategy.RETURN_DEFAULT - Source가 null인 경우 Target을 default 값으로 설정
NullValueMappingStrategy.RETURN_NULL - Source가 null인 경우 Target을 null로 설정
Source Class와 Target Class의 필드명이 동일하지 않은 경우 @Mapping 어노테이션을 사용해서 필드명을 선언
매핑하려는 필드가 객체인 경우 . 을 사용해서 객체 하위 필드에 대한 매핑
@Mapping 어노테이션의 qualifiedByName 속성과 @Named 어노테이션을 사용하면 매핑될 값에 대해 Custom 메소드로 변환이 가능
@Mapping 어노테이션의 defaultValue, defaultExpression, Ignore를 사용해서 default 값을 설정하거나 제외 가능
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface PostMapper {
// BoardPostSearchDto를 PostSearchDto로 매핑해주는 메소드
@Mapping(source = "fixPosts", target = "fixList", qualifiedByName = "mapCreatedAt")
@Mapping(source = "posts.content", target = "list", qualifiedByName = "mapCreatedAt")
@Mapping(source = "posts.number", target = "pageIndex", qualifiedByName = "setIndexFromOne")
@Mapping(source = "posts.totalPages", target = "totalPage")
@Mapping(source = "posts.size", target = "pageSize")
@Mapping(source = "posts.totalElements", target = "totalCount")
PostSearchDto postFromBoard(BoardPostSearchDto boardPostSearchDto);
// API 서버 응답의 날짜 포맷 변경
@Named("mapCreatedAt")
default List<BoardPostListDto> mapCreatedAt(List<BoardPostListDto> boardPostListDtoList) {
if (ObjectUtils.isEmpty(boardPostListDtoList)) {
return null;
}
return boardPostListDtoList.stream()
.map(boardPostListDto -> {
String convertedCreatedAt = convertDateFormat(boardPostListDto.getCreatedAt());
boardPostListDto.setCreatedAt(convertedCreatedAt);
return boardPostListDto;
})
.collect(Collectors.toList());
}
// API 서버 응답의 날짜 포맷 변경
@Named("mapCreatedAt")
default String convertDateFormat(String inputDate) {
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyyMMddHHmmss");
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
try {
return outputFormat.format(inputFormat.parse(inputDate));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
// 노출되는 페이징 인덱스 조정
@Named("setIndexFromOne")
default int setIndexFromOne(int pageIndex) {
return pageIndex + 1;
}
}
다음과 같이 PostMapper 인터페이스를 구성해서 필드명이 다른 필드 간에도 매핑이 가능하고, Custom 메소드 적용도 가능하다.
프로젝트를 진행하며 유용하게 사용했던 라이브러리인 MapStruct에 대해 알아보았다.
외부 API를 사용하여 객체 간 매핑이 많이 이뤄질 경우 사용해 보는 것도 좋을 것이다.
'Spring Boot' 카테고리의 다른 글
[Spring Boot] OTP 2차 인증 (0) | 2024.04.30 |
---|---|
[Spring Boot] @AuthenticationPrincipal 사용해서 사용자 정보 조회 (0) | 2023.12.25 |
[Spring Boot] Redis 적용해서 토큰 정보 저장 후 자동 갱신하기 (0) | 2023.12.25 |