프로젝트 중 만난 builder !!

jungnoeun·2023년 1월 8일
0

java

목록 보기
21/22

문제 발생 !!

프로젝트 중 시큐리티를 이용하여 회원가입과 로그인을 구현하던 중,
회원가입을 구현하던 중에,
@NoArgsConstructor 의 사용이 모호해지는 문제가 발생했다.

내가 사용하고 싶은 기술은 두가지였는데,
1. Mapper를 이용해서 entity -> dto 또는 dto -> entity 변화를 쉽게 사용하는 것.
2. BCryptpasswordencoder 를 사용하여, 사용자에게서 입력받은 비밀번호를 encoding하여 DB에 저장하는 것.
이었다.



하지만 에러가 발생! 그리고 해결!!

하지만,

입력을 받아오는 ReqDto에 @NoArgsConstructor 를 붙여주지 않았더니,
cannot deserialize from Object value (no delegate- or property-based Creator) 라는 에러가 발생하여,
ReqDto에 @NoArgsConstructor 를 붙여주어야 했다.

위 에러를 해결하고, 다시 실행하였더니
rawpassword cannot be null 라는 에러가 발생하였다.
이 에러의 해결방법에 대해 서치를 해보았더니,
Req Dto에 @NoArgsConstructor 를 붙여주는 것이 해결책이었다.

이 문제로 두가지 기능을 한번에 사용할 수 없을까 열심히 찾아보고 적용해보는 과정에서,
엔티티 객체에 @Builder를 붙여주었더니,
ReqDto에 @NoArgsConstructor를 붙여주어도
위 두가지 에러가 발생하지 않고 잘 실행되는 것을 확인할 수 있었다.



왜 해결??

대체 왜 해결된 것일까??


코드 변경 전후 차이

엔티티에 @Builder를 붙여줌으로써 확인할 수 있는 차이는 바로 mapper 인터페이스를 빌드하면 생기는 generated 폴더 내의
MapperImpl 코드였다.

엔티티에 @Builder를 붙여주기 전 코드는

@Override
    public Member postToMember(MemberReqDto.PostMemberReqDto postDto) {
        if ( postDto == null ) {
            return null;
        }

        String email = null;

        Member member = new Member(); //  `@NoArgsConstructor`가 전역일때	
        member.email( postDto.getEmail() );
        
        

        return member;
    }

그리고,
엔티티에 @Builder를 붙여주고난 후의 코드는 다음과 같다.

@Override
    public Member postToMember(MemberReqDto.PostMemberReqDto postDto) {
        if ( postDto == null ) {
            return null;
        }

        Member.MemberBuilder member = Member.builder();

        member.email( postDto.getEmail() );
        member.password( postDto.getPassword() );

        return member.build();
    }

에러가 난 이유

내 생각에는 @Builder를 이용해서 rawpassword cannot be null 에러를 해결한 것이라고 생각한다. 컨트롤러 코드에서 Member member = memberMapper.postToMember(postDto);라는 부분이 있는데,
postDto(ReqDto) 가 Member로 바뀌는데 에러가 발생한 것이라고 생각한다.
즉, mapper를 통해 dto가 엔티티로 바뀌는 과정에서 오류가 발생한 것이다.
하지만 엔티티에 @Builder를 붙여주니,
dto -> 엔티티 과정에서 email과 password값이 제대로 잘 들어오는 것을 알 수 있었다.

그 결과, dto에 @NoArgsConstructor 를 붙이고 rawpassword cannot be null 에러가 발생하지 않는 것을 확인할 수 있었다.



그 외 작성한 코드들(컨트롤러, 서비스)

에러가 발생했던 서비스 코드는 아래와 같다.

controller 코드

@RestController
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;
    private final MemberMapper memberMapper;


    @PostMapping("/auth/signup")
    public ResponseEntity postMember(@Valid @RequestBody MemberReqDto.PostMemberReqDto postDto) {
        Member member = memberMapper.postToMember(postDto);
        Member savedMember = memberService.postMember(member);

        return ResponseEntity.ok(memberMapper.postResMember(savedMember));
    }
}

Service 코드

@Service
@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;
    private final BCryptPasswordEncoder passwordEncoder;

    // 회원 가입
    public Member postMember(Member member) {

        String rawPassword = member.getPassword(); // encoding 전 비밀번호
        String encPassword = passwordEncoder.encode(rawPassword);

        Member changedMember = member.postFirstMember(encPassword); // 비밀번호 권한 수정

        Member savedMember = memberRepository.save(changedMember); // 저장
        return savedMember;
    }
}



참고 블로그

같은 오류가 발생한 다른 프로그래머의 다른 해결 방법
MapStruct toEntity 메서드 null 오류
https://minji6119.tistory.com/43

빌더 패턴(Builder Pattern)을 사용해야 하는 이유
https://mangkyu.tistory.com/163
Builder 패턴 - 필요성과 사용법
https://velog.io/@midas/Builder-%ED%8C%A8%ED%84%B4-%ED%95%84%EC%9A%94%EC%84%B1%EA%B3%BC-%EC%82%AC%EC%9A%A9%EB%B2%95

profile
개발자

0개의 댓글