IT/Spring & Spring Boot

[Spring Boot] RequestBody 필드에 값이 매핑되지 않는 문제

땅일단 2024. 11. 21. 22:16

역직렬화가 안돼요!

@RequestBody로 POJO 객체를 받을 때, 특정 필드에 값이 자동 매핑이 안 되는 문제가 가끔 발생한다.

즉 프론트에서 분명히 body에 {name: "doringri"} 를 담아 보냈는데 {name: ""} 로 도착하거나 한다는 것이다.

이때 boolean 형이라면 false로, int형이라면 0으로 도착할 것이다. (각 자료형의 기본값)

 

이러한 현상이 일어나면 먼저 필드의 이름이 같은지 다시 한번 확인하고, 컨트롤러에서 파라미터 앞에 @RequestBody 어노테이션을 붙였는지 확인한다.

@PostMapping
public void test(@RequestBody UserInfo userinfo) {
    ...
}

 

문제가 없다는 것을 확인했다면 매우 높은 확률로 Jackson 문제다.

Spring Boot는 내부적으로 Jackson 라이브러리를 사용해서 json을 POJO 객체로 역직렬화한다.

 

이때 객체의 필드는 보통 접근자를 private로 설정하고 Getter와 Setter를 통해 필드에 접근하는데, Jackson 또한 필드에 직접 접근하지 않고 Setter를 통해 이름을 자동으로 매핑시키기 때문에 Setter가 없다면 역직렬화를 못한다.

@Setter
public class UserInfo {
    private String name;
}

 

고로 DTO 객체에 @Setter 어노테이션이 붙어있는지 확인하자.

이래도 안된다면?

아마 필드명의 접두어가 'is' 일 가능성이 높을 것이다. ex) isActive

이건 @Setter의 명명 규칙과 Jackson의 특징 때문인데, Setter는 isXXX 필드를 XXX 로 매핑시킨다.

 

아래 코드는 Setter를 사용했을 때와 같은 동작을 하는 코드이다.

public class UserInfo {
    private boolean isActive;
    
    public void setActive(boolean active) {
    	this.isActive = active;
    }
}

 

메소드명이 setIsActive가 아닌 setActive으로 만들어진다는 점에 주목하자.

Jackson에서 setIsActive에 접근하려 했으나 해당 Setter가 없으므로 접근하지 못하는 것이다.

 

@Setter
public class UserInfo {
    @JsonProperty("isActive")
    private String isActive;
}

그래서 이 경우 @JsonProperty로 직접 매핑시켜준다면 해결된다.

 

그리고 난 이때까지 is 접두어 필드만 그런 문제가 생기는 줄 알았으나, 오늘 'aBcde' 라는 형식의 이름을 가진 필드를 매핑시키려는데 자동 매핑이 안 됐다.

 

이것도 아마 Setter의 명명 문제로 추정되는데, 두 번째 문자가 대문자인 게 문제가 되었을 것이다. Setter 메소드명이 setABcde라고 지정되었을 것이고 Jackson에서 인식할 수 있는 카멜 케이스에서 벗어난 것 같다.

 

 

 

직렬화가 안돼요!

다음 사례도 오늘 겪은 건데, ObjectMapper의 writeValueAsString으로 객체를 직렬화할 때 안 되는 경우가 있다.

위 경우와 반대인 경우로, 역직렬화에 Setter가 사용되는 것처럼 직렬화에는 Getter가 사용된다.

즉 객체에 @Getter가 안 붙어있던 게 문제였던 것이다.

 

이런 문제가 생길 수 있는 탓인지... 객체에 @Getter는 습관적으로 붙이는 사람이 많은 것 같다.