SlideShare uma empresa Scribd logo
1 de 35
Baixar para ler offline
kotlinx.
serialization
Arawn Park
SpringRunner
객체를 네트워크를 통해 전송하거나 데이터베이스 또는 파일에 저장할 수 있는 형식으로 변환하는 프로세스
!
직렬화serialization
!
자바 생태계의 직렬화 도구를 이용한 JSON 직렬화하기
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
class GsonSpec : FunSpec({
val gson = Gson()
test("객체를 JSON으로 직렬화 또는 역직렬화하기") {
val data = Movie("foo", "x", 0.1)
val serialized = gson.toJson(data)
serialized shouldBe """{"title":"foo","director":"x","rating":0.1}"""
val deserialized = gson.fromJson(serialized, Movie::class.java)
deserialized shouldBe data
}
test("리스트를 JSON으로 직렬화 또는 역직렬화하기") {
val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9))
val serialized = gson.toJson(data)
serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]"""
val javaType = object : TypeToken<List<Movie>>() {}.type
val deserialized = gson.fromJson<List<Movie>>(serialized, javaType)
deserialized shouldBe data
}
})
Kotlin/JVM
!
kotlinx.serialization으로 JSON 직렬화하기
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString
class SimpleKotlinSerializationSpec : FunSpec({
test("객체를 JSON으로 직렬화 또는 역직렬화하기") {
val data = Movie("foo", "x", 0.1)
val serialized = Json.encodeToString(data)
serialized shouldBe """{"title":"foo","director":"x","rating":0.1}"""
val deserialized = Json.decodeFromString<Movie>(serialized)
deserialized shouldBe data
}
test("리스트를 JSON으로 직렬화 또는 역직렬화하기") {
val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9))
val serialized = Json.encodeToString(data)
serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]"""
val deserialized = Json.decodeFromString<List<Movie>>(serialized)
deserialized shouldBe data
}
})
Kotlin/JVM
2017.07: kotlinx.serialization 프로젝트 시작
2017.09: 0.1 공개 (with Kotlin 1.1)
2020.10: 1.0 발표 (with Kotlin 1.4)
2022.05: 1.3 (with 1.4+)
.
.
.
왜 코틀린은 직렬화 도구를 직접 만들었을까?
!
null이 없었는데요 있었습니다
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
class GsonSpec : FunSpec({
val gson = Gson()
test("역직렬화시 널을 허용하지 않는 속성에 널을 입력해도 예외가 발생하지 않아요") {
val serialized = """{"title":"foo","rating":null}"""
val javaType = object : TypeToken<Movie>() {}.type
val deserialized = gson.fromJson<Movie>(serialized, javaType)
deserialized.title shouldBe "foo"
deserialized.director shouldBe null
deserialized.rating shouldBe 0.0
}
})
data class Movie(
val title: String,
val director: String,
val rating: Double = 1.0
)
Kotlin/JVM
!
기본이 안 돼 있네 기본이
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
class GsonSpec : FunSpec({
val gson = Gson()
test("역직렬화시 기본 인자가 설정된 속성을 지원하지 않아요") {
val serialized = """{"title":"foo","director":"x"}"""
val deserialized = gson.fromJson(serialized, Movie::class.java)
deserialized.rating shouldBe 0.0
}
})
data class Movie(
val title: String,
val director: String,
val rating: Double = 1.0
)
Kotlin/JVM
!
거 참 말 많네
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
class JacksonSpec : FunSpec({
test("데이터 클래스를 JSON으로 직렬화 또는 역직렬화하기") {
val mapper = JsonMapper.builder().build()
val data = Project("foo", 1.0)
val serialized = mapper.writeValueAsString(data)
serialized shouldBe """{"name":"foo","version":1.0}"""
val deserialized = mapper.readValue(serialized, Project::class.java)
deserialized.name shouldBe data.name
deserialized.version shouldBe data.version
}
})
data class Project @JsonCreator constructor(
@JsonProperty("name") val name: String,
@JsonProperty("version") val version: Double
)
Kotlin/JVM
!
거 참 말 많네 second edition
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.module.kotlin.kotlinModule
class JacksonSpec : FunSpec({
val mapper = JsonMapper.builder().addModule(kotlinModule()).build()
test("객체를 JSON으로 직렬화 또는 역직렬화하기") {
val data = Movie("foo", "x", 0.1)
val serialized = mapper.writeValueAsString(data)
serialized shouldBe """{"title":"foo","director":"x","rating":0.1}"""
val javaType = object: TypeReference<Movie>() {}
val deserialized = mapper.readValue(serialized, javaType)
deserialized shouldBe data
}
test("리스트를 JSON으로 직렬화 또는 역직렬화하기") {
val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9))
val serialized = mapper.writeValueAsString(data)
serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]"""
val javaType = mapper.typeFactory.constructCollectionType(List::class.java, Movie::class.java)
val deserialized = mapper.readValue<List<Movie>>(serialized, javaType)
deserialized shouldBe data
}
})
Kotlin/JVM
!
우린 너희만 있으면 돼
Browser Native
JVM Android
}
kotlinx.serialization 알아보기
!
kotlinx.serialization으로 JSON 직렬화하기
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
class SimpleKotlinSerializationSpec : FunSpec({
test("객체를 JSON으로 직렬화 또는 역직렬화하기") {
val data = Movie("foo", "x", 0.1)
val serialized = Json.encodeToString(Movie.serializer(), data)
serialized shouldBe """{"title":"foo","director":"x","rating":0.1}"""
val deserialized = Json.decodeFromString(Movie.serializer(), serialized)
deserialized shouldBe data
}
})
@Serializable
data class Movie(
val title: String,
val director: String,
val rating: Double = 1.0
)
Kotlin/JVM
!
컴파일 안전 보장 compile-time safe
import kotlinx.serialization.Serializable
class SimpleKotlinSerializationSpec : FunSpec({
test("컴파일 타임에 직렬화 지원 여부를 확인해요") {
data class User(val userName: String)
@Serializable
data class Project(
val name: String,
val owner: User,
val language: String = "Kotlin"
)
}
})
Kotlin/JVM
!
명료함 및 간결함 explicit and concise
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString
class SimpleKotlinSerializationSpec : FunSpec({
test("객체를 JSON으로 직렬화 또는 역직렬화하기") {
val data = Movie("foo", "x", 0.1)
val serialized = Json.encodeToString(data)
serialized shouldBe """{"title":"foo","director":"x","rating":0.1}"""
val deserialized = Json.decodeFromString<Movie>(serialized)
deserialized shouldBe data
}
test("리스트를 JSON으로 직렬화 또는 역직렬화하기") {
val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9))
val serialized = Json.encodeToString(data)
serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]"""
val deserialized = Json.decodeFromString<List<Movie>>(serialized)
deserialized shouldBe data
}
})
Kotlin/JVM
!
코틀린 지향 Kotlin-oriented
class SimpleKotlinSerializationSpec : FunSpec({
test("역직렬화시 널을 허용하지 않는 원시타입 속성에 널을 입력되면 예외가 발생해요") {
val exception = shouldThrow<SerializationException> {
Json.decodeFromString<Movie>("""{"title":"foo","director":"x","rating":null}""")
}
exception.message shouldBe """
Unexpected JSON token at offset 43: Failed to parse type 'double' for input 'null'
JSON input: {"title":"foo","director":"x","rating":null}
""".trimIndent()
}
test("역직렬화시 널을 허용하지 않는 속성에 널이 입력되면 예외가 발생해요") {
val exception = shouldThrow<SerializationException> {
Json.decodeFromString<Movie>("""{"title":"foo","rating":0.1}""")
}
exception.message shouldBe """
Field 'director' is required for type with serial name 'Movie', but it was missing
""".trimIndent()
}
test("역직렬화시 기본 인자가 설정된 속성을 지원해요") {
val deserialized = Json.decodeFromString<Movie>("""{"title":"foo","director":"x"}""")
deserialized.rating shouldBe 1.0
}
})
Kotlin/JVM
!
다양한 형식 지원 multi-format
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.encodeToByteArray
import kotlinx.serialization.decodeFromByteArray
class SimpleKotlinSerializationSpec : FunSpec({
test("객체를 CBOR 형식으로 직렬화 또는 역직렬화하기") {
val data = Movie("foo", "x", 0.1)
val serialized = Cbor.encodeToByteArray(data)
serialized.toAsciiHexString() shouldBe """
{BF}etitlecfoohdirectoraxfrating{FB}?{B9}{99}{99}{99}{99}{99}{9A}{FF}
""".trimIndent()
val deserialized = Cbor.decodeFromByteArray<Movie>(serialized)
deserialized shouldBe data
}
test("객체를 ProtoBuf 형식으로 직렬화 또는 역직렬화하기") {
val data = Movie("foo", "x", 0.1)
val serialized = ProtoBuf.encodeToByteArray(data)
serialized.toAsciiHexString() shouldBe """
{0A}{03}foo{12}{01}x{19}{9A}{99}{99}{99}{99}{99}{B9}?
""".trimIndent()
val deserialized = ProtoBuf.decodeFromByteArray<Movie>(serialized)
deserialized shouldBe data
}
})
Kotlin/JVM
!
멀티플랫폼 지원 multiplatform
JVM Android Browser Native
}
!
못다한 이야기...
멀티플랫폼 지원, 좀 더 가까이서 살펴보기
!
코틀린 멀티플랫폼 Kotlin Multiplatform
!
멀티플랫폼 프로젝트
!
모든 플랫폼에 공유할 로직 작성하기
Com
m
on
Kotlin
!
JS 플랫폼에서 사용할 로직 작성하기
Com
m
on
Kotlin
Kotlin/JS
!
멀티플랫폼 프로젝트 빌드하기
❯ ./gradlew clean build
Starting Build
Settings evaluated using settings file 'kotlinx-serialization/settings.gradle.kts'.
Projects loaded. Root project using build file 'kotlinx-serialization/build.gradle.kts'.

Included projects: [root project 'kotlinx-serialization']



> Task :kotlinNodeJsSetup
> Task :kotlinYarnSetup
> Task :kotlinNpmInstall
> Task :kotlinStoreYarnLock
> Task :compileKotlinJs
> Task :compileTestKotlinJs
> Task :jsTest
> Task :build



BUILD SUCCESSFUL in 1m 13s
51 actionable tasks: 45 executed, 6 up-to-date
❯ ls build/libs
kotlinx-serialization-js.klib
kotlinx-serialization-jvm.jar


❯ ls build/distributions
kotlinx-serialization.js
kotlinx-serialization.js.map
!
Kotlin/JS로 작성된 모듈을 브라우저에서 사용하기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>kotlinx-serialization</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
<script>
require(["/assets/js/kotlinx-serialization.js"], function(serialization) {
const movies = serialization.Movies
const movie = movies.fromJson('{"title":"foo","director":"x","rating":0.1}')
console.log(`Movie (title: ${movie.title}, ...)`);
});
</script>
</body>
</html>
// file:src/jsMain/kotlin/Movies.kt
object Movies {
fun fromJson(content: String) = {..}
fun fromJsonArray(content: String) = {..}
}
!
Kotlin/JS로 작성된 모듈을 Node.js에서 사용하기
const serialization = require("./modules/kotlinx-serialization.js")
const movies = serialization.Movies
const movie = movies.fromJson('{"title":"foo","director":"x","rating":0.1}')
console.log(`Movie (title: ${movie.title}, ...)`);
// file:src/jsMain/kotlin/Movies.kt
object Movies {
fun fromJson(content: String) = {..}
fun fromJsonArray(content: String) = {..}
}
!
하나의 소스로 어디든 실행 할 수 있..어요?
잠시
삼천포로
빠질게요
https://www.flickr.com/photos/revilla/515323987
나는 왜 코틀린 직렬화를 사용했나
!
우리에겐 객체 캐싱이 필요해-
" #
$
!
애플리케이션 핵심 코드를 구현 기술로부터 지켜라!
애플리케이션
핵심 코드
}
!
언어가 제공하는 도구는 침투적인 기술일까? 아닐까?
애플리케이션
핵심 코드
}kotlinx.
serialization
end.
!
reference

Mais conteúdo relacionado

Mais procurados

AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016
AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016
AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016
Amazon Web Services Korea
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing Architectures
Victor Rentea
 

Mais procurados (20)

A Web é uma API
A Web é uma APIA Web é uma API
A Web é uma API
 
Real World Event Sourcing and CQRS
Real World Event Sourcing and CQRSReal World Event Sourcing and CQRS
Real World Event Sourcing and CQRS
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Advanced Topics On Sql Injection Protection
Advanced Topics On Sql Injection ProtectionAdvanced Topics On Sql Injection Protection
Advanced Topics On Sql Injection Protection
 
AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016
AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016
AWS와 부하테스트의 절묘한 만남 :: 김무현 솔루션즈 아키텍트 :: Gaming on AWS 2016
 
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
[오픈소스컨설팅]Scouter 설치 및 사용가이드(JBoss)
 
Angular and The Case for RxJS
Angular and The Case for RxJSAngular and The Case for RxJS
Angular and The Case for RxJS
 
Asynchronous Programming in C# - Part 1
Asynchronous Programming in C# - Part 1Asynchronous Programming in C# - Part 1
Asynchronous Programming in C# - Part 1
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
 
JavaScript - Chapter 15 - Debugging Techniques
 JavaScript - Chapter 15 - Debugging Techniques JavaScript - Chapter 15 - Debugging Techniques
JavaScript - Chapter 15 - Debugging Techniques
 
JMockit Framework Overview
JMockit Framework OverviewJMockit Framework Overview
JMockit Framework Overview
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Models for hierarchical data
Models for hierarchical dataModels for hierarchical data
Models for hierarchical data
 
State management in react applications (Statecharts)
State management in react applications (Statecharts)State management in react applications (Statecharts)
State management in react applications (Statecharts)
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing Architectures
 
Code Refactoring Cheatsheet
Code Refactoring CheatsheetCode Refactoring Cheatsheet
Code Refactoring Cheatsheet
 
Streaming with Spring Cloud Stream and Apache Kafka - Soby Chacko
Streaming with Spring Cloud Stream and Apache Kafka - Soby ChackoStreaming with Spring Cloud Stream and Apache Kafka - Soby Chacko
Streaming with Spring Cloud Stream and Apache Kafka - Soby Chacko
 
Core Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug HuntCore Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug Hunt
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 

Mais de Arawn Park

Mais de Arawn Park (17)

우린 같은 곳을 바라 보고 있나요?
우린 같은 곳을 바라 보고 있나요?우린 같은 곳을 바라 보고 있나요?
우린 같은 곳을 바라 보고 있나요?
 
코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스
 
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
 
점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정
 
Introduction to Kotlin
Introduction to KotlinIntroduction to Kotlin
Introduction to Kotlin
 
Reactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/OReactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/O
 
Spring framework 4.x
Spring framework 4.xSpring framework 4.x
Spring framework 4.x
 
씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API씹고 뜯고 맛보고 즐기는 스트림 API
씹고 뜯고 맛보고 즐기는 스트림 API
 
Spring framework 3.2 > 4.0 — themes and trends
Spring framework 3.2 > 4.0 — themes and trendsSpring framework 3.2 > 4.0 — themes and trends
Spring framework 3.2 > 4.0 — themes and trends
 
overview of spring4
overview of spring4overview of spring4
overview of spring4
 
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
조금 더 좋은 개발자가 된다는 것( 부제: 컨퍼런스의 발표자가 된다는 것 )
 
Resource Handling in Spring MVC
Resource Handling in Spring MVCResource Handling in Spring MVC
Resource Handling in Spring MVC
 
[Spring Camp 2013] Java Configuration 없인 못살아!
[Spring Camp 2013] Java Configuration 없인 못살아![Spring Camp 2013] Java Configuration 없인 못살아!
[Spring Camp 2013] Java Configuration 없인 못살아!
 
Vagrant와 chef로 개발서버 구축 자동화하기
Vagrant와 chef로 개발서버 구축 자동화하기Vagrant와 chef로 개발서버 구축 자동화하기
Vagrant와 chef로 개발서버 구축 자동화하기
 

kotlinx.serialization

  • 1. kotlinx. serialization Arawn Park SpringRunner 객체를 네트워크를 통해 전송하거나 데이터베이스 또는 파일에 저장할 수 있는 형식으로 변환하는 프로세스
  • 3. ! 자바 생태계의 직렬화 도구를 이용한 JSON 직렬화하기 import com.google.gson.Gson import com.google.gson.reflect.TypeToken class GsonSpec : FunSpec({ val gson = Gson() test("객체를 JSON으로 직렬화 또는 역직렬화하기") { val data = Movie("foo", "x", 0.1) val serialized = gson.toJson(data) serialized shouldBe """{"title":"foo","director":"x","rating":0.1}""" val deserialized = gson.fromJson(serialized, Movie::class.java) deserialized shouldBe data } test("리스트를 JSON으로 직렬화 또는 역직렬화하기") { val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9)) val serialized = gson.toJson(data) serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]""" val javaType = object : TypeToken<List<Movie>>() {}.type val deserialized = gson.fromJson<List<Movie>>(serialized, javaType) deserialized shouldBe data } }) Kotlin/JVM
  • 4. ! kotlinx.serialization으로 JSON 직렬화하기 import kotlinx.serialization.json.Json import kotlinx.serialization.encodeToString import kotlinx.serialization.decodeFromString class SimpleKotlinSerializationSpec : FunSpec({ test("객체를 JSON으로 직렬화 또는 역직렬화하기") { val data = Movie("foo", "x", 0.1) val serialized = Json.encodeToString(data) serialized shouldBe """{"title":"foo","director":"x","rating":0.1}""" val deserialized = Json.decodeFromString<Movie>(serialized) deserialized shouldBe data } test("리스트를 JSON으로 직렬화 또는 역직렬화하기") { val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9)) val serialized = Json.encodeToString(data) serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]""" val deserialized = Json.decodeFromString<List<Movie>>(serialized) deserialized shouldBe data } }) Kotlin/JVM
  • 5. 2017.07: kotlinx.serialization 프로젝트 시작 2017.09: 0.1 공개 (with Kotlin 1.1) 2020.10: 1.0 발표 (with Kotlin 1.4) 2022.05: 1.3 (with 1.4+) . . .
  • 6. 왜 코틀린은 직렬화 도구를 직접 만들었을까?
  • 7. ! null이 없었는데요 있었습니다 import com.google.gson.Gson import com.google.gson.reflect.TypeToken class GsonSpec : FunSpec({ val gson = Gson() test("역직렬화시 널을 허용하지 않는 속성에 널을 입력해도 예외가 발생하지 않아요") { val serialized = """{"title":"foo","rating":null}""" val javaType = object : TypeToken<Movie>() {}.type val deserialized = gson.fromJson<Movie>(serialized, javaType) deserialized.title shouldBe "foo" deserialized.director shouldBe null deserialized.rating shouldBe 0.0 } }) data class Movie( val title: String, val director: String, val rating: Double = 1.0 ) Kotlin/JVM
  • 8. ! 기본이 안 돼 있네 기본이 import com.google.gson.Gson import com.google.gson.reflect.TypeToken class GsonSpec : FunSpec({ val gson = Gson() test("역직렬화시 기본 인자가 설정된 속성을 지원하지 않아요") { val serialized = """{"title":"foo","director":"x"}""" val deserialized = gson.fromJson(serialized, Movie::class.java) deserialized.rating shouldBe 0.0 } }) data class Movie( val title: String, val director: String, val rating: Double = 1.0 ) Kotlin/JVM
  • 9. ! 거 참 말 많네 import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty class JacksonSpec : FunSpec({ test("데이터 클래스를 JSON으로 직렬화 또는 역직렬화하기") { val mapper = JsonMapper.builder().build() val data = Project("foo", 1.0) val serialized = mapper.writeValueAsString(data) serialized shouldBe """{"name":"foo","version":1.0}""" val deserialized = mapper.readValue(serialized, Project::class.java) deserialized.name shouldBe data.name deserialized.version shouldBe data.version } }) data class Project @JsonCreator constructor( @JsonProperty("name") val name: String, @JsonProperty("version") val version: Double ) Kotlin/JVM
  • 10. ! 거 참 말 많네 second edition import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.module.kotlin.kotlinModule class JacksonSpec : FunSpec({ val mapper = JsonMapper.builder().addModule(kotlinModule()).build() test("객체를 JSON으로 직렬화 또는 역직렬화하기") { val data = Movie("foo", "x", 0.1) val serialized = mapper.writeValueAsString(data) serialized shouldBe """{"title":"foo","director":"x","rating":0.1}""" val javaType = object: TypeReference<Movie>() {} val deserialized = mapper.readValue(serialized, javaType) deserialized shouldBe data } test("리스트를 JSON으로 직렬화 또는 역직렬화하기") { val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9)) val serialized = mapper.writeValueAsString(data) serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]""" val javaType = mapper.typeFactory.constructCollectionType(List::class.java, Movie::class.java) val deserialized = mapper.readValue<List<Movie>>(serialized, javaType) deserialized shouldBe data } }) Kotlin/JVM
  • 11. ! 우린 너희만 있으면 돼 Browser Native JVM Android }
  • 13. ! kotlinx.serialization으로 JSON 직렬화하기 import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json class SimpleKotlinSerializationSpec : FunSpec({ test("객체를 JSON으로 직렬화 또는 역직렬화하기") { val data = Movie("foo", "x", 0.1) val serialized = Json.encodeToString(Movie.serializer(), data) serialized shouldBe """{"title":"foo","director":"x","rating":0.1}""" val deserialized = Json.decodeFromString(Movie.serializer(), serialized) deserialized shouldBe data } }) @Serializable data class Movie( val title: String, val director: String, val rating: Double = 1.0 ) Kotlin/JVM
  • 14. ! 컴파일 안전 보장 compile-time safe import kotlinx.serialization.Serializable class SimpleKotlinSerializationSpec : FunSpec({ test("컴파일 타임에 직렬화 지원 여부를 확인해요") { data class User(val userName: String) @Serializable data class Project( val name: String, val owner: User, val language: String = "Kotlin" ) } }) Kotlin/JVM
  • 15. ! 명료함 및 간결함 explicit and concise import kotlinx.serialization.json.Json import kotlinx.serialization.encodeToString import kotlinx.serialization.decodeFromString class SimpleKotlinSerializationSpec : FunSpec({ test("객체를 JSON으로 직렬화 또는 역직렬화하기") { val data = Movie("foo", "x", 0.1) val serialized = Json.encodeToString(data) serialized shouldBe """{"title":"foo","director":"x","rating":0.1}""" val deserialized = Json.decodeFromString<Movie>(serialized) deserialized shouldBe data } test("리스트를 JSON으로 직렬화 또는 역직렬화하기") { val data = listOf(Movie("foo", "x", 0.1), Movie("bar", "y", 9.9)) val serialized = Json.encodeToString(data) serialized shouldBe """[{"title":"foo","director":"x","rating":0.1},{..}]""" val deserialized = Json.decodeFromString<List<Movie>>(serialized) deserialized shouldBe data } }) Kotlin/JVM
  • 16. ! 코틀린 지향 Kotlin-oriented class SimpleKotlinSerializationSpec : FunSpec({ test("역직렬화시 널을 허용하지 않는 원시타입 속성에 널을 입력되면 예외가 발생해요") { val exception = shouldThrow<SerializationException> { Json.decodeFromString<Movie>("""{"title":"foo","director":"x","rating":null}""") } exception.message shouldBe """ Unexpected JSON token at offset 43: Failed to parse type 'double' for input 'null' JSON input: {"title":"foo","director":"x","rating":null} """.trimIndent() } test("역직렬화시 널을 허용하지 않는 속성에 널이 입력되면 예외가 발생해요") { val exception = shouldThrow<SerializationException> { Json.decodeFromString<Movie>("""{"title":"foo","rating":0.1}""") } exception.message shouldBe """ Field 'director' is required for type with serial name 'Movie', but it was missing """.trimIndent() } test("역직렬화시 기본 인자가 설정된 속성을 지원해요") { val deserialized = Json.decodeFromString<Movie>("""{"title":"foo","director":"x"}""") deserialized.rating shouldBe 1.0 } }) Kotlin/JVM
  • 17. ! 다양한 형식 지원 multi-format import kotlinx.serialization.cbor.Cbor import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.encodeToByteArray import kotlinx.serialization.decodeFromByteArray class SimpleKotlinSerializationSpec : FunSpec({ test("객체를 CBOR 형식으로 직렬화 또는 역직렬화하기") { val data = Movie("foo", "x", 0.1) val serialized = Cbor.encodeToByteArray(data) serialized.toAsciiHexString() shouldBe """ {BF}etitlecfoohdirectoraxfrating{FB}?{B9}{99}{99}{99}{99}{99}{9A}{FF} """.trimIndent() val deserialized = Cbor.decodeFromByteArray<Movie>(serialized) deserialized shouldBe data } test("객체를 ProtoBuf 형식으로 직렬화 또는 역직렬화하기") { val data = Movie("foo", "x", 0.1) val serialized = ProtoBuf.encodeToByteArray(data) serialized.toAsciiHexString() shouldBe """ {0A}{03}foo{12}{01}x{19}{9A}{99}{99}{99}{99}{99}{B9}? """.trimIndent() val deserialized = ProtoBuf.decodeFromByteArray<Movie>(serialized) deserialized shouldBe data } }) Kotlin/JVM
  • 18. ! 멀티플랫폼 지원 multiplatform JVM Android Browser Native }
  • 20. 멀티플랫폼 지원, 좀 더 가까이서 살펴보기
  • 23. ! 모든 플랫폼에 공유할 로직 작성하기 Com m on Kotlin
  • 24. ! JS 플랫폼에서 사용할 로직 작성하기 Com m on Kotlin Kotlin/JS
  • 25. ! 멀티플랫폼 프로젝트 빌드하기 ❯ ./gradlew clean build Starting Build Settings evaluated using settings file 'kotlinx-serialization/settings.gradle.kts'. Projects loaded. Root project using build file 'kotlinx-serialization/build.gradle.kts'.
 Included projects: [root project 'kotlinx-serialization']
 
 > Task :kotlinNodeJsSetup > Task :kotlinYarnSetup > Task :kotlinNpmInstall > Task :kotlinStoreYarnLock > Task :compileKotlinJs > Task :compileTestKotlinJs > Task :jsTest > Task :build
 
 BUILD SUCCESSFUL in 1m 13s 51 actionable tasks: 45 executed, 6 up-to-date ❯ ls build/libs kotlinx-serialization-js.klib kotlinx-serialization-jvm.jar 
 ❯ ls build/distributions kotlinx-serialization.js kotlinx-serialization.js.map
  • 26. ! Kotlin/JS로 작성된 모듈을 브라우저에서 사용하기 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>kotlinx-serialization</title> </head> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script> <script> require(["/assets/js/kotlinx-serialization.js"], function(serialization) { const movies = serialization.Movies const movie = movies.fromJson('{"title":"foo","director":"x","rating":0.1}') console.log(`Movie (title: ${movie.title}, ...)`); }); </script> </body> </html> // file:src/jsMain/kotlin/Movies.kt object Movies { fun fromJson(content: String) = {..} fun fromJsonArray(content: String) = {..} }
  • 27. ! Kotlin/JS로 작성된 모듈을 Node.js에서 사용하기 const serialization = require("./modules/kotlinx-serialization.js") const movies = serialization.Movies const movie = movies.fromJson('{"title":"foo","director":"x","rating":0.1}') console.log(`Movie (title: ${movie.title}, ...)`); // file:src/jsMain/kotlin/Movies.kt object Movies { fun fromJson(content: String) = {..} fun fromJsonArray(content: String) = {..} }
  • 28. ! 하나의 소스로 어디든 실행 할 수 있..어요?
  • 30. 나는 왜 코틀린 직렬화를 사용했나
  • 32. ! 애플리케이션 핵심 코드를 구현 기술로부터 지켜라! 애플리케이션 핵심 코드 }
  • 33. ! 언어가 제공하는 도구는 침투적인 기술일까? 아닐까? 애플리케이션 핵심 코드 }kotlinx. serialization
  • 34. end.