java.lang.NullPointerException: Cannot invoke "org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(java.lang.CharSequence)" because "this.bCryptPasswordEncoder" is null
Environment
Language: Java 17
Framework: SpringBoot 3.1.0, Spring Security 6.1.0
DB: MySQL, Redis
오류
java.lang.NullPointerException: 
Cannot invoke "org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(java.lang.CharSequence)" 
because "this.bCryptPasswordEncoder" is null
원인
@Builder
@AllArgsConstructor
@Getter
public class SignUpRequestDTO {
  private final BCryptPasswordEncoder bCryptPasswordEncoder;
  public User toEntity() {
    return User.builder()
               .status(userType.substring(0, 1).toUpperCase())
               .userType(UserType.valueOf(userType.toUpperCase()))
               .email(email)
               .phone(phone)
               .nickname(nickname)
               .password(bCryptPasswordEncoder.encode(password))
               .role(getRole())
               .build();
  }
}bCryptPasswordEncoder 인스턴스가 주입되지 않음
SignUpRequestDTO가 빈으로 등록되지 않았으므로 Spring에서는 @Bean으로 등록된 BCryptPasswordEncoder를 자동으로 주입할 수 없음
해결
1. SignUpRequestDTO을 Bean으로 등록
🚨 DTO는 일반적으로 데이터 전송 객체로 사용되며, 빈으로 관리되는 경우가 거의 없음
@Bean
@Builder
@AllArgsConstructor
@Getter
public class SignUpRequestDTO {
  private final BCryptPasswordEncoder bCryptPasswordEncoder;
  public User toEntity() {
    return User.builder()
               .status(userType.substring(0, 1).toUpperCase())
               .userType(UserType.valueOf(userType.toUpperCase()))
               .email(email)
               .phone(phone)
               .nickname(nickname)
               .password(bCryptPasswordEncoder.encode(password))
               .role(getRole())
               .build();
  }
}
2. Service 클래스에서 BCryptPasswordEncoder를 주입
UserService.java
Bean으로 등록된 UserSerivce에서 BCryptPasswordEncoder를 주입받아 SignUpRequestDTO로 전달
@Slf4j
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class UserService {
  private final BCryptPasswordEncoder bCryptPasswordEncoder;
  @Transactional
  public void create(SignUpRequestDTO signUpRequestDTO) {
    emailDuplicateCheck(signUpRequestDTO.getEmail());
    userRepository.save(signUpRequestDTO.toEntity(bCryptPasswordEncoder));
    log.info("User successfully created for email: {}", signUpRequestDTO.getEmail());
  }
}
SignUpRequestDTO.java
@Builder
@AllArgsConstructor
@Getter
public class SignUpRequestDTO {
  public User toEntity(BCryptPasswordEncoder bCryptPasswordEncoder) {
    return User.builder()
               .status(userType.substring(0, 1).toUpperCase())
               .userType(UserType.valueOf(userType.toUpperCase()))
               .email(email)
               .phone(phone)
               .nickname(nickname)
               .password(bCryptPasswordEncoder.encode(password))
               .role(getRole())
               .build();
  }
}
🙋♀️
본 포스트는 공부 목적으로 작성하였습니다.
보시는 도중 잘못된 부분이나 개선할 부분이 있다면 댓글로 알려주시면 수정하도록 하겠습니다.
📑
참고 자료
'Java > Spring with Error' 카테고리의 다른 글
| [해결 방법] Failed to determine a suitable driver class (2) | 2024.09.28 | 
|---|---|
| [해결 방법] TooManyActualInvocations (0) | 2024.09.22 | 
| [해결 방법] Argument(s) are different! (0) | 2024.09.15 | 
| [해결 방법] NoUniqueBeanDefinitionException (0) | 2024.09.04 | 
| [해결방법] io.jsonwebtoken.ExpiredJwtException (0) | 2024.08.30 |