Kotlin @Serializable 주석 읽기

Choi Sang Rok·2024년 4월 5일
0
post-thumbnail
post-custom-banner

@Serializable

Serializable 에 대해 모르고 사용하고 있는 것 같아 분석하게 되었는데, 주석에서 설명을 너무 잘해주고 있어서 이를 공유하게 되었습니다.

@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS, AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME) // Runtime is the default retention, also see KT-41082
public annotation class Serializable(
    val with: KClass<out KSerializer<*>> = KSerializer::class // Default value indicates that auto-generated serializer is used
)
The main entry point to the serialization process.
Applying [Serializable] to the Kotlin class instructs the serialization plugin to automatically generate implementation of [KSerializer]
for the current class, that can be used to serialize and deserialize the class.
The generated serializer can be accessed with `T.serializer()` extension function on the class companion,
both are generated by the plugin as well.
  • Serialization 과정의 진입점
  • Kotlin class에 Serializable 적용하면 자동으로 KSerializer 구현을 하도록 플러그인에게 지시
  • T.serializer() 처럼 해당 클래스 Companion의 확장함수로 사용 가능

@Serializable
class MyData(val myData: AnotherData, val intProperty: Int, ...)
// Produces JSON string using the generated serializer
val jsonString = Json.encodeToJson(MyData.serializer(), instance)
  • T.serializer() 를 활용하여, JSON 형식의 문자열을 생성하는 예시를 보여주고 있음
  • 이처럼 jsonString을 간편하게 생성할 때 사용할 수 있음
Additionally, the user-defined serializer can be specified using [with] parameter:

@Serializable(with = MyAnotherDataCustomSerializer::class)
class MyAnotherData(...)
MyAnotherData.serializer() // <- returns MyAnotherDataCustomSerializer
  • with parameter를 통해 커스텀 Serializer를 만들수도 있음

For annotated properties, specifying with parameter is mandatory and can be used to override serializer on the use-site without affecting the rest of the usages:
@Serializable // By default is serialized as 3 byte components
class RgbPixel(val red: Short, val green: Short, val blue: Short)

@Serializable
class RgbExample(
    @Serializable(with = RgbAsHexString::class) p1: RgpPixel, // Serialize as HEX string, e.g. #FFFF00
    @Serializable(with = RgbAsSingleInt::class) p2: RgpPixel, // Serialize as single integer, e.g. 16711680
    p3: RgpPixel // Serialize as 3 short components, e.g. { "red": 255, "green": 255, "blue": 0 }
)
In this example, each pixel will be serialized using different data representation.
  • Annotation이 사용되는 property(야기서는 p1, p2)에서 with를 지정하는 것은 필수!!
  • 여기서는 각각 p1, p2를 hexString, integer로 직렬화 되도록 재정의하였음

For classes with generic type parameters, serializer() function requires one additional argument per each generic type parameter:
@Serializable
class Box<T>(value: T)

Box.serializer() // Doesn't compile
Box.serializer(Int.serializer()) // Returns serializer for Box<Int>
Box.serializer(Box.serializer(Int.serializer())) // Returns serializer for Box<Box<Int>
  • Box.serializer()처럼 사용하면 컴파일 타임에 Not enough information to infer type variable T0 발생

  • 만약 Box 사용하고 있다면, Json.encodeToJson(Box.serializer(Int.serializer), instance) 형태로 사용 가능


In order to generate serializer function that is not a method on the particular instance, the class should have a companion object, either named or unnamed.
Companion object is generated by the plugin if it is not declared, effectively exposing both companion and serializer() method to class ABI. 
If companion object already exists, only serializer method will be generated.
  • 어떤 인스턴스에서 serializer() 함수를 생성하려면 컴패니언 객체가 있어야 함
  • 근데 어차피@Serializer 붙어있다면, 플러그인에 의해 컴패니언 객체가 생성된다.
  • 이미 있다면 직렬화 메서드만 생성된다.
profile
android_developer
post-custom-banner

0개의 댓글