본문 바로가기
Android/Kotlin

Android Jackson Library 를 이용한 JSON Parsing

by wannagohome97 2024. 1. 5.

JSON 은 REST 로 데이터를 서버로부터 받아올 때 가장 흔한 데이터 형태로

Android 에서는 이걸 파싱할 일이 정말 많은만큼 방법도 많다.

 

일단 대표적인 라이브러리로

  1. GSON
  2. Jackson

이렇게 두 가지가 있는데, 간단하게 둘을 비교하자면

 

Gson - 용량이 크지 않은 데이터 처리 작업에서 유리하고 가벼운 느낌이라면

Jackson - 대용량 데이터 처리에 강하고, 유연한 느낌이라고 할 수 있다(XML 도 지원한다)

 

오늘은 이 둘 중 Jackson Library 를 다뤄볼 것이다.

 

일단 오늘의 샘플 데이터다

 

 

const val SAMPLE = "[\n" +
        "  {\n" +
        "    \"id\": 111,\n" +
        "    \"name\": \"키보드\",\n" +
        "    \"descr\": \"일 할 때 바쁜 친구.\"\n" +
        "  },\n" +
        "  {\n" +
        "    \"id\": 222,\n" +
        "    \"name\": \"마우스\",\n" +
        "    \"descr\": \"키보드만큼 바쁜 친구\"\n" +
        "  },\n" +
        "  {\n" +
        "    \"id\": 333,\n" +
        "    \"name\": \"모니터\",\n" +
        "    \"descr\": \"사실 제일 바쁜데 조용한 친구\"\n" +
        "  }\n" +
        "]"
data class Item(
    @JsonProperty("id")
    val id: Long,
    @JsonProperty("name")
    val name: String,
    @JsonProperty("descr")
    val description: String
)

 

Jackson Library 는 기본적으로 ObjectMapper 라는 것을 사용하고

이 ObjectMapper 를 이용해 객체를 JSON으로 직렬화하거나 JSON을 String 으로 역직렬화 할 수 있다.

그러면 일단 우리는 파싱이 주 목적이었으니 역직렬화를 먼저 해보자

 

역직렬화를 할 땐 ObjectMapper 가 우선 String 을 JsonNode 라는 객체로 바꾸는데 

쉽게? 설명하자면 List나 map 처럼 바꾸는 것이다.

  • JsonNode 안에 JsonNode 들이 들어있다
  • 일반적으로 내 data Class(model class) 와 매핑시킨다고 생각하면 쉽다.

 

사실 코드를 보는게 이해가 더 쉬울 것 같다..

val objectMapper = ObjectMapper()
val dataNode: JsonNode = objectMapper.readTree(SAMPLE)
dataNode.forEach { node->
    val item = objectMapper.treeToValue(node, Item::class.java)
    println("이름: ${item.name}\n특징: ${item.description}")
}

 

이렇게 코드를 실행시키면?

 

2024-01-05 14:42:52.205 15095-15095/com.hl.test I/System.out: 이름: 키보드
2024-01-05 14:42:52.205 15095-15095/com.hl.test I/System.out: 특징: 일 할 때 가장 바쁜 친구.
2024-01-05 14:42:52.206 15095-15095/com.hl.test I/System.out: 이름: 마우스
2024-01-05 14:42:52.206 15095-15095/com.hl.test I/System.out: 특징: 키보드만큼 바쁜 친구
2024-01-05 14:42:52.207 15095-15095/com.hl.test I/System.out: 이름: 모니터
2024-01-05 14:42:52.207 15095-15095/com.hl.test I/System.out: 특징: 사실 제일 바쁜데 티는 조용한 친구

 

이런 결과를 얻어낼 수 있다.

 

반대로 직렬화 역시 가능하다

 

Item 이란 객체를 JSON으로 바꿔보자

 

val objectMapper = ObjectMapper()
val sampleItem = Item(
    id = 444,
    name = "에어팟",
    description = "주인이 일할 땐 쉬는 친구"
)
val json = objectMapper.writeValueAsString(sampleItem)
println(json)

 

이 코드를 실행시키면?

2024-01-05 14:48:46.733 15861-15861/com.hl.test I/System.out: {"id":444,"name":"에어팟","description":"주인이 일할 땐 쉬는 친구"}

 

JSON 으로 직렬화가 되었다

 

지금은 샘플이고 내가 작성했기 때문에 별 다른 문제가 없지만 보통은 위 작업을 try-catch 블록으로 감싸주는데 그 것만으로는 해결이 안되는 예외가 있다.

  1. API 로 확인했던것 외의 프로퍼티가 추가로 오는 상황
  2. 와야할 프로퍼티 가 안 오는 상황

위 상황에선 crash 가 발생하는 경우도 있기 때문에 별도로 처리를 해줘야 하는데

기본적으로 1번의 경우 아래와 같이 작성해주면 쉽게 처리가 가능하다

@JsonIgnoreProperties(ignoreUnknown = true)
data class Item(
    @JsonProperty("id")
	...

 

대략 영어를 해석해보면 알 수 있듯이 모르는 프로퍼티 는 무시해버린다는 조건을 달아주는 것이다.

이러면 1번에 대한 예외는 끝났고 2번의 경우다.

@JsonIgnoreProperties(value = ["property_1", "property_2"], allowSetters = false)
data class Item(
    @JsonProperty("id")
	...

 

Jackson 에 매핑시키는 모델 클래스를 Java 로 구현해보면 기본적으로 Jackson 은

 

  • JsonNode 의 각 값을
  • model class
  • 각 field에
  • setter 로

달아주는 형태이다(그래서 Java 에선 getter/setter를 모두 작성해야 하고 프로퍼티가 많으면 별 내용도 없이 모델 클래스의 코드 길이가 엄청 길어진다)

 

그렇기 때문에 모르는 프로퍼티에 대해선 setter 를 허용하지 않는 조건까지 같이 달아줌으로써

 

2번에 해당하는 예외를 처리할 수 있다.