이 장은 Kotlin Serialization 가이드의 두 번째 장입니다. 모든 원시(primitive) 타입 및 문자열 외에도 표준 컬렉션을 비롯해 Kotlin 표준 라이브러리의 일부 클래스에 대한 직렬화가 Kotlin 직렬화 플러그인에 내장되어 있습니다. 이번 장에서는 이러한 빌트인 클래스에 대한 자세한 내용을 설명합니다.

원시(primitive) 타입

Kotlin 직렬화는 다음의 10가지의 원시 타입을 가지고 있습니다. Boolean, Byte, Short, Int, Long, Float, Double, Char, String, 그리고 열거형(enum)입니다. Kotlin 직렬화에서의 다른 타입들은 이러한 원시값으로 구성된 복합 형태입니다.

숫자

Kotlin 직렬화는 모든 타입의 정수 및 부동 소수점(floating-point) 숫자를 직렬화할 수 있습니다.

결과는 다음과 같습니다.

{"answer":42,"pi":3.141592653589793}

긴 숫자

긴 정수 역시 직렬화할 수 있습니다.

기본적으로 JSON에서 숫자로 직렬화됩니다.

{"signature":2067120338512882656}

긴 숫자를 문자열로 변환

이전 예제의 JSON 출력은 Kotlin/JS에서 실행되는 Kotlin 직렬화에 의해 정상적으로 디코딩됩니다. 하지만 네이티브 JavaScript 메서드를 통해 이 JSON을 파싱하면 다음과 같이 일부 값이 잘린 결과가 나타납니다.

JSON.parse("{\"signature\":2067120338512882656}")
▶ {signature: 2067120338512882700} 

Kotlin Long의 전체 범위는 JavaScript 숫자 범위보다 크기 때문에 JavaScript 에서 정밀도(precision)가 손실됩니다. 이런 경우에 일반적인 해결 방법은 긴 숫자를 전체 정밀도를 유지하는 문자열 유형으로 표현하는 것입니다. 이 방법은 해당 Long 프로퍼티에 @Serializable 어노테이션의 LongAsStringSerializer 값을 지정하는 방식으로 사용 가능합니다.

이제 JSON은 정밀도 손실 없이 자바스크립트에서 기본적으로 파싱가능합니다.

{"signature":"2067120338512882656"}

Info

Specifying serializers for a file 섹션에서는 파일의 모든 프로퍼티에 대해 LongAsStringSerializer와 같은 serializer를 지정하는 방법에 대해 설명합니다.

열거형 클래스

다음 예제에서 볼 수 있듯이 모든 열거형 클래스는 @Serializable을 표시하지 않고도 바로 직렬화할 수 있습니다. All enum classes are serializable out of the box without having to mark them @Serializable, as the following example shows.

JSON에서 enum은 문자열로 인코딩됩니다.

{"name":"kotlinx.serialization","status":"SUPPORTED"}

Note

Kotlin/JS와 Kotlin/Native 에서는 enum 클래스를 root 객체로 사용(예를 들어, encodeToString<Status>(Status.SUPPORTED)와 같이 사용)하려면 @Serializable 어노테이션이 필요합니다.

열거형 항목의 serial 이름

열거형 항목의 serial 이름은 Serial 필드명항목에서 프로퍼티에 대해 설정한 것과 마찬가지로 SerialName 어노테이션을 통해 사용자 지정할 수 있습니다. 단, 이 경우 전체 열거형 클래스에 @Serializable 어노테이션을 표시해야 합니다.

결과를 보면 JSON 결과에 @SerialName에 지정된 값이 사용된 것을 확인할 수 있습니다.

{"name":"kotlinx.serialization","status":"maintained"}

복합 유형

Kotlin 표준 라이브러리의 여러 복합적인 유형들도 Kotlin 직렬화에서 지원됩니다.

Pair와 triple

Kotlin 표준 라이브러리의 간단한 데이터 클래스 PairTriple은 직렬화할 수 있습니다.

결과는 다음과 같습니다.

{"first":1,"second":{"name":"kotlinx.serialization"}}

Info

Kotlin 표준 라이브러리의 모든 클래스를 직렬화할 수 있는 것은 아닙니다. 특히 range와 Regex 클래스는 현재 직렬화할 수 없습니다. 추후에 해당 클래스에 대한 직렬화 지원이 추가될 수 있습니다.

List

직렬화 가능한 클래스로 구성된 List를 직렬화할 수 있습니다.

결과는 JSON의 List 형태로 표시됩니다.

[{"name":"kotlinx.serialization"},{"name":"kotlinx.coroutines"}]

Set 외 다른 컬렉션

Set와 같은 다른 컬렉션도 직렬화할 수 있습니다.

Set 역시 다른 모든 컬렉션들과 마찬가지로 JSON에서 List 형태로 표시됩니다.

[{"name":"kotlinx.serialization"},{"name":"kotlinx.coroutines"}]

컬렉션의 역직렬화

역직렬화할 때 결과 객체의 타입은 소스 코드에 지정된 정적 타입(프로퍼티의 타입 또는 디코딩 함수의 타입 파라미터에 의해 결정됩니다. 다음 예제는 동일한 정수 list가 서로 다른 두가지 Kotlin 프로퍼티로 역직렬화되는 방법을 보여 줍니다.

data.b 프로퍼티는 중복값을 허용하지 않는 Set이기 때문에 중복된 값이 사라집니다.

Data(a=[42, 42], b=[42])

Map

원시타입 또는 열거형타입의 키와 임의의 직렬화 가능한 값을 가진 Map을 직렬화할 수 있습니다.

JSON에서 Kotlin Map 타입은 객체로 표현됩니다. JSON에서 객체 키는 반드시 문자열이기 때문에 아래에서 볼 수 있듯이 키는 Kotlin에서 숫자인 경우에도 문자열로 인코딩됩니다.

{"1":{"name":"kotlinx.serialization"},"2":{"name":"kotlinx.coroutines"}}

Info

키를 복합적으로 사용할 수 없는 것은 JSON 특유의 제약사항 입니다. 이 제약은 Allowing structured map keys 항목에 나와있는 방법을 통해 해제할 수 있습니다.

Unit과 singleton 객체

Kotlin에 내장된 Unit 타입도 직렬화할 수 있습니다. Unit은 Kotlin 싱글톤 객체이며 다른 Kotlin 객체와 동일하게 처리됩니다.

개념적으로 싱글톤은 인스턴스가 하나만 존재하는 클래스로, 상태가 객체를 정의하는 것이 아니라 객체가 상태를 정의하는 것을 의미합니다. 따라서, JSON에서 싱글톤 객체는 빈 구조로 직렬화됩니다.

이는 언뜻 쓸모없어 보일 수 있지만, Polymorphism. Objects 섹션에서 설명하는 sealed 클래스 직렬화에 유용하게 쓰입니다.

{}
{}

Info

객체의 직렬화는 포맷에 따라 다릅니다. 포맷은 정규화된 이름을 사용하는 등으로 객체를 다르게 표현할 수 있습니다.

Duration

Kotlin 버전 1.7.20부터 Duration 클래스를 직렬화할 수 있게 되었습니다.

Duration은 ISO-8601-2 형식의 문자열로 직렬화됩니다.

"PT16M40S"

Nothing

기본적으로 Nothing은 직렬화 가능한 클래스입니다. 그러나 이 클래스의 인스턴스가 없기 때문에 값을 인코딩하거나 디코딩하는 것은 불가능하며 시도할 경우 예외가 발생합니다.

이 serializer는 구문상 어떤 타입이 필요할 때 사용하지만 실제로 직렬화에는 사용하지 않습니다. 예를 들어 다음과 같이 파라미터화된 다형성 베이스 클래스를 사용할 때 사용합니다:

위의 예제를 인코딩하면, Nothing에 대한 serializer는 사용되지 않습니다.

{"value":42}

다음 장에서는 Serializer에 대해 설명합니다.