본문 바로가기

카테고리 없음

boolean 타입 'is' 생략 없이 json 직렬화하기 (with Lombok)

문제

간단한 controller를 만들다 원시 타입의 boolean을 json으로 직렬화하는 과정에서 문제가 생겼다. DTO의 필드명이 isXXX였는데 is가 자꾸 빠져서 직렬화되었다.

 

'isGood'이 'good'이 되어버리는 마-직

 

실패한 첫 접근 방법 : @JsonProperty를 사용해보자!

@JsonProperty는 json 필드의 이름을 지정할 수 있는 애노테이션이다. 이를 통해 이름을 'isXXX'로 지정해두면 이 문제를 쉽게 해결할 수 있을줄 알았다. 하지만..

 

??? 이번엔 필드가 두 개가 되어버렸다

 

갑자기 json에 good과 isGood 두 개의 값이 생겼다. 원인은 롬복의 @Getter 애노테이션이었다. 이 현상을 이해하려면 먼저 두 가지 사실을 알아야 한다.

 

1. Jackson은 기본적으로 직렬화, 역직렬화 과정에서 getter/setter를 이용한다.

2. 롬복의 @Getter는 'is'로 시작하는 원시 타입의 boolean 필드 getter를 생성할 때 이름을 'getIsXXX'가 아닌 'isXXX'로 만든다.

 

MyResponse DTO의 바이트 코드. getter 이름이 필드명과 같은 'isGood'인 것을 확인할 수 있다.

 

이 두가지가 합쳐져서 JsonProperty에서 지정한 필드 이름인 'isGood'이 생기고, getter를 찾아보니 'isGood'이라는 getter가 존재해서 'is'를 생략한 'good'이라는 필드가 중복으로 생긴 것이다. 거참 복잡하네.

 

해결 1. wrapper 타입의 boolean을 사용한다.

primitive 타입이 아닌 wrapper 타입의 boolean을 사용하면 'is'가 생략되지 않는다.

 

'isGood'이 그대로 잘 나온다

 

하지만 응답 DTO에 wrapper 타입을 사용하면 null이 들어갈 수 있다. null을 허용하지 않는 값이라면 원시 타입을 사용하는 것이 개발자의 혼란을 줄일 수 있다. 따라서 null이 될 수 없는 값인데 필드 이름을 위해 wrapper 타입을 사용하는 것은 별로 추천하고 싶지 않다.

 

해결 2. Lombok에게 특정 필드의 getter를 생략하라고 한다.

롬복에게 getter 생성을 맡기지 않고 직접 getter를 만들 수도 있다. 필드에 @Getter 애노테이션을 붙이고 AccessLevel을 None으로 주면 롬복이 getter를 생성하지 않는다.

 

'getIsGood'이라는 getter를 직접 정의했다.

 

하지만 이 방법을 사용하면 불필요하게 애노테이션과 getter 코드가 추가된다는 불편함이 있다. 필드명 하나때문에 이렇게까지 해야하나..하는 회의감이 드는 방법이랄까.

 

결론

가장 확실한 방법은 isXXX라는 변수명을 피하는 것이다. XXXStatus 등의 이름으로 대체하는 것이 현명한 방법인 것 같다ㅎ.