본문 바로가기
Spring/series

[spring 1편] mapstruct 활용

by 무대포 개발자 2022. 6. 13.
728x90
반응형

source 는 Github 에 있습니다.

목차는 spring series 목차 에 있습니다.

[spring 1편] mapstruct 활용

mapstruct 무엇인가?

  • mapstruct 은 객체 맵핑을 도와주는 라이브러리입니다.
  • 예를 들면, dto <-> dto 간 코드 맵핑을 도와주는 것입니다.

source

  • 단건을 mapping 하는 예제와 list 를 맵핑하는 예제로 테스트 작성했습니다.
  • build.gradle
// MapStruct
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor "org.mapstruct:mapstruct-processor:1.4.2.Final"
annotationProcessor(
        'org.projectlombok:lombok',
        'org.projectlombok:lombok-mapstruct-binding:0.1.0'
)
  • dto source
@Getter @Setter
@NoArgsConstructor
@ToString
public class SimpleDto {
    private String key;
    private String name;

    @Builder
    public SimpleDto(String key, String name) {
        this.key = key;
        this.name = name;
    }

    @Getter
    public static class Request {
        private final String key;
        private final String name;

        @Builder
        public Request(String key, String name) {
            this.key = key;
            this.name = name;
        }
    }

    @Setter
    @Getter
    @ToString
    public static class ListRequest {
        private String key;
        private List<Item> itemList;

        @Builder
        public ListRequest(String key, List<Item> itemList) {
            this.key = key;
            this.itemList = itemList;
        }
    }

    @Setter
    @Getter
    @Builder
    @ToString
    public static class Item {
        private String itemName;
    }
}


public class SimpleCommand {
    @Getter @Setter
    @ToString
    public static class Request {
        private final String key;
        private final String name;

        public Request(String key, String name) {
            this.key = key;
            this.name = name;
        }
    }

    @Getter @Setter
    @ToString
    public static class ListRequest {
        private final String key;
        private final List<Item> items;

        public ListRequest(String key, List<Item> items) {
            this.key = key;
            this.items = items;
        }
    }

    @Getter @Setter
    @ToString
    public static class Item {
        private final String itemName;

        public Item(String itemName) {
            this.itemName = itemName;
        }
    }
}

  • mapper
@Mapper(
        componentModel = "spring",  // spring component bean 등록
        injectionStrategy = InjectionStrategy.CONSTRUCTOR,  // 생성자 주입 방식 사용
        unmappedTargetPolicy = ReportingPolicy.ERROR    // mapping 없으면 에러
)
public interface SimpleDtoMapper {

    SimpleDtoMapper INSTANCE = Mappers.getMapper(SimpleDtoMapper.class);

    // list 없음
    SimpleCommand.Request of (SimpleDto.Request request);

    @Mapping(source = "request.key", target = "key")
    @Mapping(target = "name", ignore = true)
    @Mapping(source = "testIntValue", target = "intValue")
    SimpleCommand.RequestV2 of(SimpleDto.Request request, int testIntValue);

    // request 에 list 존재
    @Mappings({@Mapping(source = "itemList", target = "items")})
    SimpleCommand.ListRequest of (SimpleDto.ListRequest request);

}

  • test source
public class SimpleDtoMapperTest {

    @Test
    public void 단건_mapper_test() throws Exception {
        SimpleDto.Request request = SimpleDto.Request.builder()
                .key("keytest")
                .name("keyName")
                .build();

        SimpleCommand.Request result = INSTANCE.of(request);
        Assert.assertEquals("keytest", result.getKey());
    }

    @Test
    public void List_mapper_test() throws Exception {
        SimpleDto.Item item = SimpleDto.Item.builder()
                .itemName("item1")
                .build();
        List<SimpleDto.Item> itemsList = new ArrayList<>();
        itemsList.add(item);
        SimpleDto.ListRequest request = SimpleDto.ListRequest.builder()
                .key("keyTest")
                .itemList(itemsList)
                .build();

        SimpleCommand.ListRequest result = INSTANCE.of(request);
        Assert.assertEquals("keyTest", result.getKey());
        Assert.assertEquals("item1", result.getItems().get(0).getItemName());
    }

    @Test
    public void 아규먼트_다건_mapper_테스트() {
        // given
        SimpleDto.Request request = SimpleDto.Request.builder()
                .key("keytest")
                .name("keyName")
                .build();

        final int testIntValue = 25;

        SimpleCommand.RequestV2 result = INSTANCE.of(request, testIntValue);
        Assert.assertEquals("keytest", result.getKey());
        Assert.assertEquals(25, result.getIntValue());
    }
}

결론

  • mapstruct 사용하면 dto 간 데이터 전송을 쉽게 할 수 있으며, 코드도 간결해집니다.

Reference

댓글