프로젝트 중 시큐리티를 이용하여 회원가입과 로그인을 구현하던 중,
회원가입을 구현하던 중에,
@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