최근 gson 으로 직렬화/역직렬화를 수행하였던 프로젝트를 kotlinx-serialization 로 migration하는 리팩토링을 수행하였다
잘쓰던 gson 을 냅두고 kotlinx-serialization을 왜 사용하게 되었는지에 대해선 이미 좋은 글이 있기에 해당 글의 링크를 첨부하는 것으로 설명을 대체하도록 하겠다.
신입 안드로이드 개발자의 kotlinx-serialization-리팩토링 서사시
순조롭게 리팩토링을 진행하던 중, 아래와 같은 data class에서 문제를 직면하게 되었다.
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.util.Date
@Serializable
data class KakaoImageSearchDocument(
@SerialName("collection")
val collection: String,
@SerialName("datetime")
val datetime: Date, // <- 문제 발생 지점
@SerialName("display_sitename")
val siteName: String,
@SerialName("doc_url")
val url: String,
@SerialName("height")
val height: Int,
@SerialName("image_url")
val imageUrl: String,
@SerialName("thumbnail_url")
val thumbnailUrl: String,
@SerialName("width")
val width: Int
)
Serializer has not been found for type 'Date'. To use context serializer as fallback, explicitly annotate type or property with @Contextual
Date type 을 직렬화할 수 없다는 의미의 에러였고, 커스텀 직렬화 클래스를 만들어서 직렬화를 수행하거나, @Contextual annotation을 붙히는 등의 해결책들을 찾을 수 있었다.
하지만 Date type 자체가 Java의 것이고 날짜, 시간등의 정보를 가져올 수 있는 레거시 라이브러리 이기에 이를 kotlin의 Instant 으로 변경해보기로 하였다.
코틀린의 라이브러리니까 지원을 해줄 것이라 생각했지만, 다음과 같은 에러를 뱉었다.
Serializer has not been found for type '[Error type: Unresolved type for Instant]'. To use context serializer as fallback, explicitly annotate type or property with @Contextual
kotlinx-Serialization 은 비교적 간단한 타입들의 대한 직렬화, 역직렬화를 제공해주고, Java의 Date, Kotlin의 LocalDate, LocalDateTime, Instant 와 같은 primitive가 아닌 타입에 대해선 제공을 해주지 않았다..
이에 대한 해결법을 찾기위해, 구글링 및 위에 신입 안드로이드 개발자의 kotlinx-serialization-리팩토링 서사시 글을 참고한 결과
kotlinx-datetime 라이브러리를 직렬화를 수행해야하는 모듈의 build.gradle 에 추가하면 성공적으로 직렬화를 수행할 수 있다는 글을 확인할 수 있었고, 라이브러리를 추가, import 하여 에러를 없앨 수 있었다.
package com.kenshi.data.model.image
import kotlinx.datetime.LocalDate
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
// 기존의 자바의 Date 를, kotlin Serialization 적용을 위해 kotlin 의 LocalDate 로 변경
// kotlinx-datetime 라이브러리 적용
@Serializable
data class KakaoImageSearchDocument(
@SerialName("collection")
val collection: String,
@SerialName("datetime")
val datetime: Instant,
@SerialName("display_sitename")
val siteName: String,
@SerialName("doc_url")
val url: String,
@SerialName("height")
val height: Int,
@SerialName("image_url")
val imageUrl: String,
@SerialName("thumbnail_url")
val thumbnailUrl: String,
@SerialName("width")
val width: Int
)
Java 의 Date 클래스와 호환되는 클래스는 kotlinx-datetime 의 Instant 이기 때문에 Instant 로 변경해주었고, 정상적으로 response 를 받아올 수 있었다.
참고 자료)
https://blog.mathpresso.com/신입-안드로이드-개발자의-kotlinx-serialization-리팩토링-서사시-740597911e2e
https://github.com/Kotlin/kotlinx.serialization#dependency-on-the-json-library
https://github.com/Kotlin/kotlinx-datetime#using-in-your-projects
https://blog.jetbrains.com/kotlin/2021/05/kotlinx-datetime-0-2-0-is-out/