[Java/Jackson] JSON 변환시 boolean 필드의 ‘is’가 사라지는 이유와 해결법

Spring Boot로 개발을 하다 보면 의도치 않게 JSON 응답 필드명이 예상과 다르게 전달되는 경우가 있다. 특히 boolean 타입 변수명을 사용할 때 많이 겪는 문제다.
예를 들어

@Getter
public class UserDto {
    private boolean isActive; // 활성 상태
}
Java

컨트롤러를 통해서 UserDto를 전송할 때 {“isActive”: true} 가 응답할 것이라고 예상을 할 것이다. 하지만 실제로는 다음과 같이 응답한다.

{
    "active": true
}
JSON

어라? ‘is’는 대체 어디로 사라졌단 말인가? 이 현상을 모르고 넘어가면 프런트엔드와의 연동 과정에서 불필요한 커뮤니케이션 비용이 발생할 수 있다.
이번 포스팅에서는 boolean 필드의 ‘is’가 사라지는 이유와 해결법을 알아보고 Primitive Type(boolean)과 Wrapper Class(Boolean)를 사용할 때의 결정적인 차이에 대해서 정리하고자 한다.

boolean 필드의 ‘is’가 사라지는 이유

Jackson 이나 Lombok 라이브러리는 ‘JavaBeans 규약’을 따르는데 이 규약이 boolean타입을 다루는 방식이 조금 독특하다. Jackson은 객체를 직렬화 할 때 필드 자체가 아닌 Getter메서드를 기준으로 이름을 결정한다. ‘JavaBeans 규약’에 따르면 boolean 타입의 Getter는 is를 접두사로 사용하는데 Jackson은 이 is를 필드 이름이 아닌 규약상의 접두사로 판단하여 제거하고 나머지 이름인 ‘active’만 사용하게 되는 것이다.
만약 Lombok을 사용하여 @Getter를 지정했을 때 boolean 타입을 사용한다면 isXXX()와 같이 ‘is’가 접두사로 붙게 된다.
하지만 Primitive Type인 boolean과 Wrapper Class인 Boolean 중에 어떤 타입을 사용하느냐에 따라 차이가 있다.

타입필드명생성되는 GetterJSON 결과
boolean (primitive)isActiveisActive()active
Boolean (wrapper)isActivegetIsActive()isActive

해결 방법

  • Wrapper 클래스 타입 (Boolean) 사용
    • 기본형인 boolean 타입을 사용하는 대신에 Boolean을 사용하면 lombok은 getIsActive()를 생성하고 Jackson은 isActive라는 이름을 그대로 유지할 수 있다. 물론 Boolean을 사용하는 경우 null 처리를 잘 해줘야 한다.
private Boolean isActive;
Java
  • @JsonProperty 어노테이션 활용
    • 타입과 상관없이 JSON 키 값을 강제로 지정하는 방법으로 그냥 이것저것 생각할 것이 가장 깔끔하다.
@JsonProperty("isActive")
private boolean isActive;
Java
  • 필드명에서 ‘is’ 제거하기
    • 애초에 필드명을 ‘active’로 짓고 필요할 때만 is를 붙여서 읽는 방식이다. 자바 표준에 가장 부합하는 깔끔한 네이밍 방식이다.
private boolean active;
// Getter는 isActive()가 되면 JSON은 {"active": true}
Java
  • Gson 라이브러리 사용 (이를 해결하기 위해 사용하는 것은 강력하게 비추!!!)
    • Gson은 리플렉션 방식으로 DTO의 변수 이름을 그대로 사용하기 때문에 ‘is’가 사라지는 문제가 발생하지 않는다.
    • 하지만 DTO를 직렬화, 역직렬화가 필요한 곳에서 jackson -> gson으로 변경하는 일은 배보다 배꼽이 더 큰 형국이 될 것 같다.
Jackson(Default)Gson
기본접근 방식Getter 메서드 기준필드(변수명) 기준
JavaBeans 규약엄격히 따름 (is 제거)따르지 않음
isActive 처리 결과activeisActive

DTO 에서 boolean 타입의 필드의 경우 ‘is’를 붙이지 않는 것이 자바 표준에 부합하는 네이밍 방식이고 이러한 is가 사라지는 이슈도 신경쓰지 않아도 되는 깔끔한 방법인 것 같다.

부득이 하게 isActive와 같이 붙여야 하는 상황이라면 @JsonProperty 어노테이션으로 확실히 이름을 정해 주도록 하자.

boolean 필드의 is가 왜 사라지는지 그리고 어떻게 해결하면 되는지 정리해 보았는데, 내용은 아주 간단하지만 자칫하면 삽질의 길로 갈 수도 있는 포인트이니 알아둬서 나쁠건 없을 것 같다.

추가)

mongodb에 저장될 Document에 boolean 타입으로 isXXX 필드를 지정해서 테스트 해 보았다. 결과는 정상적으로 isXXX 필드명으로 입력되었다. 이유는 mongodb에 저장하는 것은 Spring Data MongoDB의 영역이라 동작 방식이 다르기 때문이다.
Spring Data MongoDB는 기본적으로 Getter가 아닌 Reflection을 사용하여 변수 자체에 접근하여 직렬화를 하기 때문이다.
그렇다고 하더라도 isXXX와 같이 꼭 ‘is’를 붙여야 하는 경우가 아니라면 그냥 고민없이 is를 떼고 이름을 정의하는 것이 좋겠다는 생각이다.