2 분 소요

Jackson 라이브러리로 json 데이터를 객체로 쉽게 변환할 수 있다.
변환하는 과정에서 종종 의도대로 변환이 안됐던 적이 있어서 케이스 별로 나눠서 테스트 코드를 만들어봤다.
객체로 변환하는 메서드는 readValue()를 사용할 것이다.

의존성은 아래와 같이 설정했다.

implementation("com.fasterxml.jackson.core:jackson-core:2.15.2")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2")
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2")


name, age, email 이라는 필드를 갖는 간단한 클래스 Person을 정의해주자.
age, email에는 기본값이 있지만, name에는 기본값이 없는 점을 유의하자.

data class Person(
    val name: String, // 기본값 없음
    val age: Int = 0,
    val email: String = "test@email.com",
)


케이스 별로 나눠보기

필드 값이 모두 있을 때

name, age, email에 모두 값을 정상적으로 채워주면 파싱도 정상적으로 되는걸 확인할 수 있다.

@Test
fun `json 값을 객체로 파싱할  있다`() {
    val input = """
        {
            "name": "John",
            "age": 20,
            "email": ""
        }
        """.trimIndent()

    jacksonObjectMapper().readValue(input, Person::class.java).also {
        assertEquals("John", it.name)
        assertEquals(20, it.age)
        assertEquals("", it.email)
    } // true
}


매칭되지 않는 필드 값이 있을 때

name, age, email 외에 Person에 없던 필드가 json에 있으면 어떻게 될까? unknown이라는 필드를 추가해보자.
과연 파싱이 잘 될까?

없던 필드는 엄격하게 체크를 하는지, UnrecognizedPropertyException를 던진다.

@Test
fun `json 값에서 파싱할  매칭되지 않는 필드는 설정을 해주지 않으면 무시할  없다`() {
    val input = """
        {
            "name": "John",
            "age": 20,
            "email": "",
            "unknown": "field" // 추가
        }
        """.trimIndent()

    // 없던 필드가 생겨서 UnrecognizedPropertyException 를 던진다.
    assertThrows(UnrecognizedPropertyException::class.java) {
        jacksonObjectMapper().readValue(input, Person::class.java)
    }
}


result type(Person)에 안맞으면 DatabindException을 던진다고 나와있다.

?
  • 참고로 예외 연관관계는 아래와 같다.
  • UnrecognizedPropertyException → PropertyBindingException → MismatchedInputException → JsonMappingException → DatabindException

아래처럼 FAIL_ON_UNKNOWN_PROPERTIES 설정을 false로 없는 필드는 무시할 수 있다!
DeserializationFeature.java 에서 FAIL_ON_UNKNOWN_PROPERTIES의 기본값은 true다.
그래서 처음에 파싱이 안된 것이다.

@Test
fun `json 값에서 파싱할  매칭되지 않는 필드는 설정해주면 무시할  있다`() {
    val input = """
        {
            "name": "John",
            "age": 20,
            "email": "",
            "unknown": "field"
        }
        """.trimIndent()

    jacksonObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) // 추가
        .readValue(input, Person::class.java)
        .also {
            assertEquals("John", it.name)
            assertEquals(20, it.age)
            assertEquals("", it.email)
        }
}


기본값이 없는 필드만 있을 때

기본값이 없는 필드는 반드시 값이 있어야 객체 생성이 되기 때문에, 값을 채워줘야 한다.
기본값이 있는 필드는 json 데이터에 없으면 기본값으로 채워진다. (age는 0, email은 test@email.com)

@Test
fun `기본값이 없는 필드만 채워주면 json 파싱에 성공한다`() {
    val input = """
        {
            "name": "John"
        }
        """.trimIndent()

    // true
    jacksonObjectMapper().readValue(input, Person::class.java).also {
        assertEquals("John", it.name)
        assertEquals(0, it.age)
        assertEquals("test@email.com", it.email)
    }
}
  • jacksonObjectMapper대신 ObjectMapper를 사용하면 InvalidDefinitionException를 던진다.

기본값이 없는 필드(name)이 없으면 파싱에 실패하면서 JsonProcessingException를 던지게 된다.

@Test
fun `기본값이 없는 필드를 채우지 않으면 json 파싱에 실패한다`() {
    val input = """
        {
            "age": 20,
            "email": ""
        }
        """.trimIndent()

    // 기본값이 없는 필드 name의 값을 못채우니 파싱에 실패한다. (JsonProcessingException)
    assertThrows(JsonProcessingException::class.java) {
        jacksonObjectMapper().readValue(input, Person::class.java)
    }
}

카테고리:

업데이트:

댓글남기기