안드로이드/Network

JSON Converter Library

snaildeveloper 2025. 5. 20. 12:08

JSON이란?

JavaScript 객체 문법으로 구조화 된 데이터 교환 형식

{
    "name": "홍길동",
    "age": 20
}

 

직렬화 & 역직렬화

직렬화 : 외부의 시스템에서도 사용할 수 있도록 바이트 형태로 데이터를 변환하는 기술
역직렬화: 바이트 형태의 데이터를 객체로 변환하는 기술

 

서버에서 데이터를 받을 때 혹은 유저가 서버에 데이터를 보낼 때 주로 JSON형식으로 데이터를 변환하여 서로 주고 받는다.

사용자가 데이터를 전송할 때 해당 데이터를 JSON으로 변환하여 보내줄 필요가 있는데 이를 직렬화(Serialization)라고 하며, 

반대로 JSON으로 넘어온 데이터를 그대로 사용하기 어려우니 JSON형식의 데이터를 나의 환경에 맞는 데이터 형식으로 바꿔주는 것역직렬화(DeSerialization)이라고 한다.

 

라이브러리 종류

1. Gson

  • Java 기반 라이브러리
  • 리플렉션 사용
  • Kotlin의 null-safety를 고려하지 않음
  • Default Value가 적용되지 않음
{
    "name": "홍길동",
    "age": 20,
    "phone_number": "010-1234-5678"
}
data class User(
    val name: String,
    val age: Int,
    val phoneNumber: String,
    val address: String
)

Json 데이터를 User 객체로 변환 시 Json에 없는 address 값은 null로 넘어온다.

이때, address는 non-null 인데 값은 null이 들어가게 되는 문제가 생긴다. 

data class User(
    val name: String,
    val age: Int,
    val phoneNumber: String,
    val address: String = "서울특별시"
)

이를 위해 address에 default value를 지정 후 변환해도 Gson은 default value 값이 적용되지 않는다.

따라서 Gson을 사용하는 경우 Nullable하게 선언해주어야 하며, Null Check를 해주어야 한다.

 

2. Kotlinx Serialization

  • 리플렉션 미사용
  • Default Value 적용
  • null-safety

Gson에 대한 대안으로 Kotlinx-Serialization이 있다.

 

속성

import kotlinx.serialization.json.Json

fun serializationJson(){
    Json {
         ignoreUnknownKeys = true
         coerceInputValues = true
         encodeDefaults = true
         explicitNulls = true
         isLenient = true
    }
}

 

[DeSerialization]

  • ignoreUnknownKeys: 추가적인 Json 키가 존재하는 경우 이를 무시한다.
{
    "name": "홍길동",
    "age": 20,
    "address": "서울"
}

@Serialization
data class User(
    val name: String,
    val age: Int
)

 

 

  • coerceInputValues: 데이터 타입이 non-null이며, 해당 키의 값이 null이라면 Default Value 값 적용
    (해당 속성이 false이며, non-null 타입에 null이 들어오면 에러 발생)
{
    "name": "홍길동",
    "age": 20,
    "address": null
}

@Serialization
data class User(
    val name: String,
    val age: Int,
    val address: String = "주소"
)
  • isLenient: Json의 Key와 Value가 따옴표로 구성되지 않은 경우에도 파싱할 수 있다.
{
    name: 홍길동,
    age: 20,
    address: 서울
}

@Serialization
data class User(
    val name: String,
    val age: Int,
    val address: String
)

 

 

[Serialization]

  • encodeDefaults: Json 변환 시 Defalut Value 적용
    (해당 속성 false 시, Defalut Value 필드는 생략되어 변환된다.)
@Serialization
data class User(
    val name: String,
    val age: Int = 20,
    val address: String = "주소"
)

fun main(){
    val format = Json { encodeDefaults = true }
    val user = User("홍길동")
    val json = format.encodeToString(user)
    println(json)
}

// 결과
{
    "name": "홍길동",
    "age": 20,
    "address": "주소"
}

// encodeDefault = false 결과
{
    "name": "홍길동"
}
  • explicitNulls: null 필드는 Json으로 변환 시 생략한다.
@Serialization
data class User(
    val name: String,
    val age: Int,
    val address: String?
)

fun main(){
    val format = Json { explicitNulls = true }
    val user = User("홍길동", 20, null)
    val json = format.encodeToString(user)
    println(json)
}

// 결과
{
    "name": "홍길동",
    "age": 20
}

 

이외의 다양한 Json 속성들은 https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md 참고

 

3. Moshi

  • 리플렉션을 사용하지 않고 컴파일 타임에 클래스 필드 타입 정보를 확인하여 빠른 성능을 보여준다.
  • Kotlin 높은 호환성
  • Gson을 차용하여 개발되어 큰 문제없이 Gson에서 Moshi로 이전이 가능하다.
  • Okio 기반으로 개발되어 강력한 I/O 처리를 제공해주어 성능에 큰 이점을 갖는다.
  • Retrofit과 함께 사용했을 경우 메모리 버퍼를 재사용하여 메모리 할당 및 해제에 드는 오버헤드 감소 효과

(참고 자료:  https://blog.imqa.io/json-moshi/ )

 

Moshi vs Kotlinx-Serialization에 대한 내용

https://medium.com/@kacper.wojciechowski/moshi-vs-kotlinx-serialization-the-ultimate-benchmark-a7ed776a46c0