Mapstruct 리팩토링 - leegwichan/StackOverFlow_Refactoring GitHub Wiki

◎ 기존 작성 방법

  • 강사님에게 배웠던 방법대로 작성
    • field name이 같은 것들 끼리 mapping이 이루어진다.
  • 이외 방법은 하나씩 해보면서 함
    • interface에서 default를 이용해서 수동 구현

◎ 기존 작성 방법의 문제점

  • 알려준 방법만을 사용하고 다른 기능들을 사용하지 않음
    • 다른 Mapper의 mapping 결과를 가져가다 쓸 수 없음
    • field의 이름이 다를 때도 수동으로 Mapping을 함
    • field의 다른 결과 값을 집어넣지 못함
  • 수동으로 구현한 method가 많아서 DTO, Entity 변경에 취약함

◎ Refactoring 중점 사항

  • Mapstruct 공식 문서를 참고하여 다음과 같은 방법을 찾음
    • 다른 Mapper의 method를 가져다가 사용하는 방법 : @Mapper(uses = {AnotherMapper.class})
    • 이름이 다른 field끼리의 Mapping : @Mapping(target = "member.memberId", source = "memberId")
    • field에 다른 결과 값을 집어 넣기 : @Mapping(target = "answerCount", expression = "java(question.getAnswers().size())")
    • 해당 사항들은 블로그에 정리 // 블로그 보완 필요해 보임

◎ Refactoring 효과

  • 중복 코드 감소 (관련 코드 58% 감소)
  • Mapstruct에서 제공하는 다양한 기능 사용

◎ Code 전후 비교

// 변경 전
@Mapper(componentModel = "spring")
public interface QuestionMapper {

    default Question questionPostDtoToQuestion(QuestionDto.Post post){
         Question question = new Question();
         question.setTitle(post.getTitle());
         question.setContent(post.getContent());

         Member memberData = new Member();
         memberData.setMemberId(post.getMemberId());
         question.setMember(memberData);

         return question;
    }
    Question questionPatchDtoToQuestion(QuestionDto.Patch patch);
    default QuestionDto.Response questionToQuestionResponseDto(Question question){

        Answer bestAnswer = question.getBestAnswer();
        return new QuestionDto.Response(
                question.getQuestionId(),
                question.getTitle(),
                question.getContent(),
                question.getView(),
                question.getVote(),
                question.getCreatedAt(),
                question.getModifiedAt(),
                memberToMemberSubResponseDto(question.getMember()),
                answersToAnswerResponseDtos(question.getAnswers()),
                question.getAnswers().size(),
                bestAnswer != null ? bestAnswer.getAnswerId() : null
        );
    };
    default List<QuestionDto.SubResponse> questionsToQuestionSubResponseDtos(List<Question> question){
        return question.stream()
                .map(question1 -> questionToQuestionSubResponseDto(question1))
                .collect(Collectors.toList());
    }
    default QuestionDto.SubResponse questionToQuestionSubResponseDto(Question question){

        Answer bestAnswer = question.getBestAnswer();


        return new QuestionDto.SubResponse(
                question.getQuestionId(),
                question.getTitle(),
                question.getContent(),
                question.getView(),
                question.getVote(),
                question.getCreatedAt(),
                question.getModifiedAt(),
                memberToMemberSubResponseDto(question.getMember()),
                question.getAnswers().size(),
                bestAnswer != null ? bestAnswer.getAnswerId() : null
        );
    }

    MemberDto.SubResponse memberToMemberSubResponseDto(Member member);
    List<AnswerDto.Response> answersToAnswerResponseDtos(List<Answer> answer);
}
// 변경 후
@Mapper(componentModel = "spring", uses = {MemberMapper.class, AnswerMapper.class})
public interface QuestionMapper {

    @Mapping(target = "member.memberId", source = "memberId")
    Question questionPostDtoToQuestion(QuestionDto.Post post);

    Question questionPatchDtoToQuestion(QuestionDto.Patch patch);

    @Mapping(target = "answerCount", expression = "java(question.getAnswers().size())")
    @Mapping(target = "bestAnswerId",
            expression = "java(question.getBestAnswer() != null ? question.getBestAnswer().getAnswerId() : null)")
    QuestionDto.Response questionToQuestionResponseDto(Question question);

    @Mapping(target = "answerCount", expression = "java(question.getAnswers().size())")
    @Mapping(target = "bestAnswerId",
            expression = "java(question.getBestAnswer() != null ? question.getBestAnswer().getAnswerId() : null)")
    QuestionDto.SubResponse questionToQuestionSubResponseDto(Question question);
    List<QuestionDto.SubResponse> questionsToQuestionSubResponseDtos(List<Question> question);
}
⚠️ **GitHub.com Fallback** ⚠️