Kotlinx Serialization

CmplxN·2021년 1월 18일
1

kotlinx.serialization
jet brains 발표
블로그 포스트
블로그 포스트

일단 간단하고 핵심적인 내용만 훑어봤다.

Serialization

Kotlin을 쓰면서 JSON (역)직렬화를 한다면 Jackson / Gson / Moshi 셋 중 하나를 쓰고 있었을 것이다.
Kotlin은 Java랑 100% 호환성이 있다고 하지만, 이 라이브러리들은 주의없이 사용하면 예상치 못한 결과를 볼 수 있다.
안드로이드가 자바기반이라 커스텀 뷰 생성자를 default 값으로 한번에 만들 때 @JvmOverloads를 붙여주듯이 신경 써줄 부분이 있다.

java가 아닌 kotlin 기반

  • Jackson / Gson / Moshi는 Optional field나 default value를 쓸 수 없다.
  • Jackson / Gson / Moshi는 아래 data class의 default value를 무시하고 0 또는 null로 (역)직렬화한다.
data class User(
    val name: String,
    val email: String,
    val age: Int = 13,
    val role: Role = Role.Viewer
)
enum class Role { Viewer, Editor, Owner }

val user = Gson().fromJson(jsonString, User::class.java)
{
    "name" : "John Doe",
    "email" : "john.doe@email.com"
}
  • 위 예제에서 age는 defualt value를 무시하고 0이 되며, role은 아예 null이 되어 앱이 터져버린다.

kotlinx serialization으로 변경

  • kotlinx serialization을 위한 의존성을 추가하고, 아까 유저 모델을 다시 만들어보자.
@Serializable // Annotation 추가
data class User(
    val name: String,
    val email: String,
    val age: Int = 13,
    val role: Role = Role.Viewer
)
enum class Role { Viewer, Editor, Owner }

val user = Json.parse(User.serializer(), jsonString)
  • 이제는 default value가 적용되고 crash가 나지 않음을 확인할 수 있다.

Polymorphic serialization

  • 상속 구조를 파악해서 (역)직렬화가 편하다.
@Serializable
sealed class Message {
   abstract val content: String
}

@Serializable
data class BroadcastMessage(override val content: String) : Message()

@Serializable
data class DirectMessage(override val content: String, val recipient: String) : Message()

val data: List<Message> = listOf(
   DirectMessage("Hey, Joe!", "Joe"),
   BroadcastMessage("Hey, all!")
)
val string = Json.encodeToString(data)
println(string)
// [{"type":"DirectMessage","content":"Hey, Joe!","recipient":"Joe"},{"type":"BroadcastMessage","content":"Hey, all!"}]

val obj = Json.decodeFromString<List<Message>>(string)
println(obj)
// [DirectMessage(content=Hey, Joe!, recipient=Joe), BroadcastMessage(content=Hey, all!)]
  • 위 예제에서 sealed class와 상속한 클래스의 구조를 파악(json의 type)해서 직렬화한다.
  • type 필드를 이용해서 원래 타입으로 역직렬화된다.

kotlinx serialization의 장점

  • kotlin을 위한 라이브러리로, KMM, kotlin/js, kotlin/native에서도 쓸 수 있다.
  • 잘못 작성된 코드는 런타임이 아닌 컴파일 에러로 잡힌다. (@Serializable을 누락했다던가)
  • 내부 동작에서 reflection을 썼던 Jackson / Gson / Moshi와 달리 reflection을 사용하지 않는다.
  • 윗줄에서 이어지는 것인데, 제네릭 타입의 (역)직렬화에서 Type을 넘겨주지 않아도 된다. (특히 컬렉션)
  • Strong Customizability (@SerialName, @Transient 등)
  • Framework integration이 용이하다. 예를 들면 Retrofit에서도 addConverterFactory()로 손쉽게 추가할 수 있다. (Jake Wharton)
profile
Android Developer

1개의 댓글

comment-user-thumbnail
2023년 7월 6일

moshi 사용하면서 테스트코드를 작성해보았습니다. default value가 적용이 되는데 혹시 어떤 resource를 보고 default value가 적용이 안된다고 하셨는지 궁급합니다!

답글 달기