기본 생성자가 없음에도 @RequestBody를 통해 Java 객체가 올바르게 생성되었다. 기본적으로 리플렉션과 기본 생성자를 사용해 매핑된다고 알고 있었기에 의문이 들었다.
@Getter
@Builder
public class SignupRequest {
@NotBlank(message = "Email is required")
@Email(message = "Invalid email format")
private String email;
@NotBlank(message = "Password is required")
@Size(min = 6, max = 20, message = "Password must be between 6 and 20 characters")
private String password;
@NotBlank(message = "Username is required")
private String username;
}
@RequestBody
Spring MVC에서 @RequestBody는 HTTP 요청의 본문(body)을 Java 객체로 역직렬화(Deserialize) 하는 데 사용됩니다. 이 과정에서 기본적으로 Jackson 라이브러리가 사용됩니다.
- @RequestBody는 HTTP 요청의 본문을 읽어와 JSON 데이터를 Java 객체로 변환합니다.
- 변환 과정에서 Spring은 HttpMessageConverter를 사용하며, 기본적으로 Jackson이 등록되어 있습니다.

Jackson
Jackson은 기본적으로 Java Bean 규칙에 따라 JSON 필드와 Java 객체를 매핑하며, getter와 setter 메서드를 사용하는 프로퍼티 기반 매핑 방식을 따릅니다. 따라서, Jackson은 객체의 필드가 아닌 getXXX와 setXXX 메서드를 통해 데이터를 매핑합니다.
프로퍼티
- Java Bean 표준에 따라 정의된, 객체의 데이터를 표현하고 접근할 수 있는 방법.
- 일반적으로 Getter, Setter 메서드를 통해 정의.
역직렬화 매핑 과정
1. AbstractMessageConverterMethodArgumentResolver의 readWithMessageConverters
readWithMessageConverters에서는 각종 메타 정보들을 확인하고 mapping 해줄 converter를 결정한다.

등록된 컨버터 목록을 순회하며 적합한 컨버터를 찾는다. 각 컨버터는 두 가지 기준에 따라 요청을 처리할 수 있는지 확인한다.
- 지원하는 Content-Type
- 지원하는 Java 객체 타입

converter 중 MappingJackson2HttpMessageConverter가 선택이 된다. converter가 결정되면 코드에서 볼 수 있듯이 read 메서드를 통해 body 값을 읽어온다.
2. deserializeFromObject()
해당 메서드에서 생성자에 따른 분기 처리가 일어난다.
- 기본 생성자가 있는 경우 (createUsingDefault)
- 기본 생성자가 없는 경우 (deserializeFromObjectUsingNonDefault)

3. deserializeFromObjectUsingNonDefault()
기본 생성자 대신 프로퍼티로 필드를 매핑한다.

@JsonCreator나 @JsonProperty 어노테이션을 사용해 생성자나 필드를 지정하지 않았더라도, ParameterNamesModule 덕분에 property-based 메서드가 호출됩니다.
Method called to deserialize bean using "property-based creator": this means that a non-default constructor or factory method is called, and then possibly other setters. The trick is that values for creator method need to be buffered, first; and due to non-guaranteed ordering possibly some other properties as well.

ParameterNamesModule 모듈을 사용하려면 의존성을 추가하거나 ObjectMapper에 설정해주어야 하는데, spring-boot-starter-web에서는 의존성이 추가되어서 따로 추가하지 않아도 적용된다.

'Programming > Spring' 카테고리의 다른 글
| Autowired (0) | 2024.12.11 |
|---|---|
| ApplicationContext 2가지 빈 설정 방식 (0) | 2024.12.11 |
| MapStruct & Lombok 적용 (0) | 2022.05.04 |
| @JsonProperty, @JsonNaming (0) | 2022.04.29 |
| Entity, DTO, VO 차이 (0) | 2022.02.04 |