IT/개발로그

[Java] Jackson 사용시 Getter를 주의하자

김솔샤르 2022. 3. 14. 21:36

짧고 담백하게 결론부터 말하자면 자바에서 Jackson 라이브러리를 사용하여 json 문자열로 Serialize 할때는 getter를 주의해야한다. 예를 들어 아래와 같은 클래스가 있다고 하자.

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Product {
    private long id;
    private String name;
    private long price;

    public String getProductInfo(){
        return name + price;
    }
}

멤버 변수로 정의한 것은 id, name, price이고 편의상 getProductInfo()라는 메서드를 만들어 상품의 이름과 가격을 함께 리턴하도록 했다. 이 상태로 객체를 json으로 변환하면 어떻게 될까?

    @Test
    public void test_writeValueAsString() throws JsonProcessingException {
        Product product = Product.builder()
                                 .id(1)
                                 .name(TEST_PRODUCT)
                                 .price(1000)
                                 .build();

        String productInfoJson = new ObjectMapper().writeValueAsString(product);
        System.out.println(productInfoJson);
    }

의도한 대로면 id, name, price를 필드로 가지는 json 문자열이 나와야 하는데 결과를 보면 이상한게 들어가 있다.

{"id":1,"name":"KEYBOARD","price":1000,"productInfo":"KEYBOARD1000"}

뜻밖에도 productInfo라는 필드가 포함되어 있다. 이유는 jackson이 객체를 읽어들일때 getter를 통해 접근하기 때문이다. 필드 하나 더 들어가는 것쯤 상관없을 수도 있으나 이런 데이터가 어딘가에 저장이 되어야한다면, 그리고 그 데이터가 수십~수백만건이라면 분명 낭비가 될 것이다.  심지어 해당 json 문자열을 다시 읽어들여 자바 객체로 deserialize 할때는 인식되지 않은 필드라면서 어처구니 없는 파싱 에러를 낸다.(그럴거면 애초에 serialize 하지도 말았어야지?)

 

 

해결 방법은 serialize 대상이 아닌 필드나 메서드에 아래와 같이 @JsonIgnore를 붙여주면 된다. 그러면 Jackson이 serialize 대상이 아닌 것으로 판단하여 제외한다.

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Product {
    private long id;

    private String name;

    private long price;

    @JsonIgnore
    public String getProductInfo(){
        return name + price;
    }
}

또는 그냥 Gson을 쓰면 알아서 필드만 Serialize 해준다. 메서드명도 훨씬 간결하고 직관적이다. 또한 Exception을 뱉지도 않아서 명시적으로 처리를 해줄 필요도 없다! (갓 Gson)

    @Test
    public void test_toJson() {
        Product product = Product.builder()
                                 .id(1)
                                 .name(TEST_PRODUCT)
                                 .price(1000)
                                 .build();

        System.out.println(new Gson().toJson(product));
    }

 

결론 : 모두 Gson을 씁시다.

반응형