티스토리 뷰

Java

Jackson 2.9.1~2.9.3 @JsonProperty 버그

LichKing 2018. 1. 13. 20:05
바로 앞선 포스팅에서 Jackson 2.9 버전에 대해 알아봤다. 이 이슈를 해결하다가 알게된 버그인데 포스팅하고자한다.

1. 이슈

일단 앞선 이슈를 해결하기위해 Jackson 버전을 올렸는데 CI 서버가 테스트를 실행하면서 다른 곳의 테스트가 실패하는 이슈가 발생했다. json 문자열을 자바 객체로 역직렬화(deserialization)하는 테스트였는데 이런 코드였다.


public class DeserializeTest {
private ObjectMapper objectMapper;

@Before
public void setUp() {
this.objectMapper = new ObjectMapper();
}

@Test
public void test() throws IOException {
String json = "{\"car\":\"\"}";

TestClass result = this.objectMapper.readValue(json, TestClass.class);

assertThat(result.getCar(), is(nullValue()));
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public static class TestClass {
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Car car;
}

enum Car {
SONATA, AVANTE
}
}


car 필드가 json 안에 있는데 ""(empty string, 빈 문자열)로 들어있는게 문제의 원인이다. 해당 필드를 enum으로 역직렬화를 해야하는데 ""이니 특정 인스턴스로 변환을 할 수가 없었던 것이다. 테스트 케이스에서는 null로 변환되길 기대했지만 분명 null과 ""는 다르니 예외가 발생하는게 맞는것같은 느낌이 든다. 일단 이 이슈는 ObjectMapper의 설정을 통해 해결할 수 있다.


@Before
public void setUp() {
this.objectMapper = new ObjectMapper();
this.objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
}


명칭이 참 직관적이다. 이 설정을 추가해주면 ""을 null로 변환해준다. 테스트 케이스는 성공하는걸 볼 수 있다. 


2. 원인

하지만 이게 정말 해법일까? 여기서 상기해야할점은 Jackson 버전을 올리기전에는 정상작동하던 코드라는 점이다. 2가지 이유로 인해 좀 더 파봤다.


* ObjectMapper 의 설정을 바꾸는건 전역적인 역직렬화 옵션이 바뀌는것이기때문에 옵션을 변경하는것에 부담을 느꼈다.

* ACCEPT_EMPTY_STRING_AS_NULL_OBJECT 옵션은 2.9 에 새로이 추가된것이 아니다. 저 옵션을 설정해줘야하는 것이라면 2.8 버전에서도 넣어줬어야 했을것이다. 좀 더 구체적인 원인이 뭔지 궁금했다.


주의깊게 본 사람도 있겠지만 저 코드에서 간과하고있는 부분이 하나 있었다. Car 변수에 붙어있는 애노테이션을 확인해보자.


@JsonProperty(access = JsonProperty.Access.READ_ONLY)


@JsonProperty 애노테이션에 인자로 READ_ONLY 를 전달하고있다. 이 옵션은 '해당 필드를 직렬화(serialization) 할때만 사용한다.' 라는 의미이다.


/**
* Access setting that means that the property may only be read for serialization,
* but not written (set) during deserialization.
*/
READ_ONLY,


즉 지금처럼 역직렬화 할때는 이 필드를 전혀 신경쓰지않고 값이 있든 없든 null 로 채우게된다. 지금 이슈처럼 역직렬화를 시도하려고하는 그 자체가 문제인것이다.


3. 해결

일단 Jackson 버전을 올릴때 가장 최신인 2.9.3 버전을 사용했는데 2.9.0 버전에서는 해당 버그가 발생하지않고, 원하는 신규기능은 사용할 수 있어 2.9.0 버전을 사용하는것으로 타협을 봤다. 그리고 이 이슈는 Jackson 에 이슈 등록을 했으니 수정해주길 기다려야겠다. 이 버그때문에 이직 이후 처음으로 밤 늦게까지 남게됐는데 나같은 삽질을 하는사람이 한명이라도 줄길 바란다.


#2018.02.05 추가

이슈 등록했는데 롬복프로젝트는 취급안한다고해서 롬복제거하고 다시 테스트했다. 그런데 이게 왠걸? 확실히 롬복지우고 내가 직접 생성자를 만드니 버그가 발생하지않는것이 아닌가? 롬복이 만들어주는 생성자와 내가 만든생성자가 다른게 있을거라는 생각에 각각의 자바 파일을 직접 컴파일하고 역컴파일하여 코드를 비교했다. 롬복이 만들어주는 생성자에는 특정 애노테이션(@ConstructorProperties)이 붙어있는걸 확인할 수 있었다. 직접 정의하는 생성자에도 저 애노테이션을 붙이면 동일한 문제가 발생했다.


그래서 이런내용도 정리하고 이슈를 다시 올렸는데 여기까지 해보니 이슈등록만 할게 아니라 코드를 직접 수정해보자는 생각에 수정하고 PR 올렸다. 그리고 얼마전에 merge가 됐다. 이렇게 오픈소스에 기여를 하게됐다.^^


https://github.com/FasterXML/jackson-databind/pull/1891

댓글
댓글쓰기 폼