본문 바로가기
Spring

@RequestBody 에서 필드가 하나 인 DTO의 필드가 null인 오류

by 김노카 2024. 6. 25.

⚠️ 에러 사항

Contoller에서 @RequestBody를 통해 DTO 클래스로 데이터를 받아와서 사용하는중 DTO클래스의 필드가 null으로 오류가 발생하는 상황

AuthContoller

@RestController
@RequiredArgsConstructor
@RequestMapping("api/v1/user/auth")
public class AuthController {
    private final UserAuthService userAuthService;
                                        ┅
    @PostMapping("/reissue")
    public ResponseEntity<?> reissue(@RequestBody RefreshTokenDto refreshTokenDto) {
        return ResponseEntity.status(HttpStatus.OK)
                .body(new DefaultResponse<>(200, "reissue access token", userAuthService.reIssue(refreshTokenDto)));
    }
}

RefreshTokenDto

@Builder
@Getter
public class RefreshTokenDto {
    private String refreshToken;
}

오류가 발생한 코드는 위와 같다.

평소와 같이 DTO 클래스에는 @Builder, @Getter 어노테이션만 작성하고 사용했는데 해당 컨트롤러로 요청을 했을때 refreshToken이 null이라는 오류가 발생해서 원하는 동작이 하지 않았다.

왜 다른 DTO 클래스들은 필드가 null이라는 오류가 발생하지 않는데 해당 DTO 클래스는 필드가 null이라는 오류가 발생할까?

@RequestBody 어노테이션이 JSON Request를 처리하는 방법을 알면 필드가 null인 이유에 대해서 알 수 있다.

@RequestBody 어노테이션이 JSON Request를 처리하는 방법

@RequestBody 어노테이션은 JSON -> Java 객체로 바꾸어 객체의 형태로 사용할 수 있다.

JSON -> Java 객체의 행위를 역직렬화(Deserializion) 라고 한다.

Spring Boot에서 직렬화, 역직렬화를 진행하는 방법

Spring은 Jackson 라이브러리 안에 있는 ObjectMapper를 사용하여 Java 객체 -> JSON으로 직렬화 혹은 JSON -> Java 객체로 역직렬화를 진행한다.

직렬화의 조건

직렬화화의 조건은 각 필드에 대한 Getter 메소드를 정의 하는것이다.

역직렬화의 조건

역직렬화를 하기 위한 조건은 기본생성자를 만들어 줘야한다. 그렇다면 이때까지 DTO를 만들어서 @RequestBody 를 사용했을때는 오류가 발생하지 않았을까?

필드가 두개 이상인 클래스에서는 jackson-module-parameter-names 모듈에서(Spring Boot 2.x 이후 버전에서는 자동으로 등록이 되어 있음)
ParameterNamesModule 클래스가 JsonCreator 를 사용해 기본생성자가 없는 객체도 역직렬화가 가능하게 설정해준다.

필드가 하나인 경우에는 JsonCreator의 Mode를 어떤 것을 설정하지 정하지 못해서 오류가 발생한다. (Delegating 생성자인지, Property-based creator인지 구분할 수 없다.)

✅ 해결

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class RefreshTokenDto {
    private String refreshToken;
}

DTO 클래스에 기본생성자를 만들어서 사용을 하면 @RequestBody 를 이용한 역직렬화를 성공적으로 진행을 한다.

Spring Boot를 사용하지 않았다면 필드가 두 개 이상인 클래스에서도 역직렬화 관련 문제가 발생했을 것이다. 반드시 역직렬화를 하기 위해서는 기본생성자를 만들어줘야 한다.

Reference

https://velog.io/@hgo641/Spring%EC%97%90%EC%84%9C%EC%9D%98-%EC%A7%81%EB%A0%AC%ED%99%94JSON-parse-error-%ED%95%84%EB%93%9C%EA%B0%80-%ED%95%98%EB%82%98%EB%B0%96%EC%97%90-%EC%97%86%EB%8A%94-DTO

 

Spring에서의 직렬화

Spring은 ObjectMapper라는 클래스를 사용해 Json값을 Spring의 자바 객체로 변환한다. spring-boot-starter-web을 gradle에 의존성으로 추가하면 jackson이라는 라이브러리도 함께 가져오는데, jackson안에 ObjectMa

velog.io

https://dukcode.github.io/spring/spring-dto/#spring-boot-autoconfiguration

 

[개발고민] Spring DTO는 어떻게 작성하고 변환해야 할까?

💡 개발고민은 개발을 공부하며 했던 저의 생각들 입니다. 정답이 아니며 정답을 찾아가는 과정이라고 봐주시면 감사하겠습니다. Github Repository Spring DTO는 어떻게 작성하고 변환해야 할까?

dukcode.github.io