Slide 1

Slide 1 text

Say “hi” to zsmb.co zsmb13 Márton Braun Moshi

Slide 2

Slide 2 text

@zsmb13

Slide 3

Slide 3 text

Serialization @zsmb13

Slide 4

Slide 4 text

JSON Serialization @zsmb13

Slide 5

Slide 5 text

JSON Serialization on the JVM @zsmb13

Slide 6

Slide 6 text

@zsmb13

Slide 7

Slide 7 text

@zsmb13

Slide 8

Slide 8 text

@zsmb13

Slide 9

Slide 9 text

@zsmb13

Slide 10

Slide 10 text

Gson github.com/google/gson @zsmb13

Slide 11

Slide 11 text

Gson 101 @zsmb13

Slide 12

Slide 12 text

Gson 101 val burger: Burger = Gson().fromJson("{...}", Burger::class.java) @zsmb13

Slide 13

Slide 13 text

Gson 101 val burger: Burger = Gson().fromJson("{...}", Burger::class.java) val json: String = Gson().toJson(Burger()) @zsmb13

Slide 14

Slide 14 text

Gson 101 val burger: Burger = Gson().fromJson("{...}", Burger::class.java) val json: String = Gson().toJson(Burger()) @zsmb13

Slide 15

Slide 15 text

Gson 101 val burger: Burger = Gson().fromJson("{...}", Burger::class.java) val json: String = Gson().toJson(Burger()) @zsmb13

Slide 16

Slide 16 text

Gson 101 val gson = Gson() val burger: Burger = Gson().fromJson("{...}", Burger::class.java) val json: String = Gson().toJson(Burger()) @zsmb13

Slide 17

Slide 17 text

Gson 101 val gson = Gson() val burger: Burger = gson.fromJson("{...}", Burger::class.java) val json: String = gson.toJson(Burger()) @zsmb13

Slide 18

Slide 18 text

Gson val gson = Gson() val burger: Burger = gson.fromJson("{...}", Burger::class.java) val json: String = gson.toJson(Burger()) 101 @zsmb13

Slide 19

Slide 19 text

Gson val gson = Gson() : built-in types @zsmb13

Slide 20

Slide 20 text

Gson val gson = Gson() gson.toJson(Date()) : built-in types @zsmb13 "Oct 29, 2021 : : PM" 04 08 9

Slide 21

Slide 21 text

Gson val gson = Gson() gson.toJson(Date()) "Oct 29, 2021 : : PM" : built-in types @zsmb13 04 20 9

Slide 22

Slide 22 text

Gson val gson = Gson() gson.toJson(Date()) "Oct 29, 2021 : : PM" : built-in types @zsmb13 04 24 9 gson.toJson(Calendar.getInstance()) , 21 04 24 {"year":2021,"month":9,"dayOfMonth":29,"hourOfDay": "minute": ,"second": }

Slide 23

Slide 23 text

Gson val gson = Gson() gson.toJson(Date()) "Oct 29, 2021 : : PM" gson.toJson(Calendar.getInstance()) {"year":2021,"month":9,"dayOfMonth":29,"hourOfDay": "minute": ,"second": } : built-in types @zsmb13 , 21 04 37 04 37 9

Slide 24

Slide 24 text

Gson val gson = Gson() gson.toJson(Date()) "Oct 29, 2021 : : PM" gson.toJson(Calendar.getInstance()) {"year":2021,"month":9,"dayOfMonth":29,"hourOfDay": "minute": ,"second": } : built-in types @zsmb13 21 04 40 9 , 04 40 gson.toJson(Random())

Slide 25

Slide 25 text

Gson val gson = Gson() gson.toJson(Date()) "Oct 29, 2021 : : PM" gson.toJson(Calendar.getInstance()) {"year":2021,"month":9,"dayOfMonth":29,"hourOfDay": "minute": ,"second": } : built-in types @zsmb13 21 04 55 9 , 04 55 gson.toJson(Random()) {"seed":{"value":137564286790437},"nextNextGaussian":0.0, "haveNextNextGaussian":false}

Slide 26

Slide 26 text

Gson: field naming val gson = Gson() @zsmb13

Slide 27

Slide 27 text

Gson: field naming val gson = GsonBuilder() .create() @zsmb13

Slide 28

Slide 28 text

val gson = GsonBuilder() .setFieldNamingPolicy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create() Gson: field naming @zsmb13

Slide 29

Slide 29 text

val gson = GsonBuilder() .setFieldNamingPolicy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create() Gson: field naming data class Burger( val name: String, val totalCost: Int, val salesPrice: Int ) @zsmb13

Slide 30

Slide 30 text

val gson = GsonBuilder() .setFieldNamingPolicy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create() Gson: field naming data class Burger( val name: String, val totalCost: Int, val salesPrice: Int ) gson.toJson(Burger("Classic", 10, 13)) @zsmb13

Slide 31

Slide 31 text

val gson = GsonBuilder() .setFieldNamingPolicy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create() Gson: field naming data class Burger( val name: String, val totalCost: Int, val salesPrice: Int ) gson.toJson(Burger("Classic", 10, 13)) {"name":"Classic","total_cost":10,"sales_price":13} @zsmb13

Slide 32

Slide 32 text

GsonBuilder() .setFieldNamingPolicy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create() Gson: field naming gson.toJson(Burger("Classic", 10, 13)) {"name":"Classic","total_cost":10,"sales_price":13} val gson = data class Burger( val name: String, val totalCost: Int, val salesPrice: Int ) @zsmb13

Slide 33

Slide 33 text

@SerializedName("name") @SerializedName("total_cost") @SerializedName("sales_price") Gson() Gson: field naming gson.toJson(Burger("Classic", 10, 13)) {"name":"Classic","total_cost":10,"sales_price":13} data class Burger( val gson = val name: String, val totalCost: Int, ) val salesPrice: Int @zsmb13

Slide 34

Slide 34 text

Gson: missing data Gson() val gson = @zsmb13

Slide 35

Slide 35 text

data class Burger( val name: String, val price: Int ) Gson: missing data Gson() val gson = @zsmb13

Slide 36

Slide 36 text

data class Burger( val name: String, val price: Int ) Gson: missing data val burger = gson.fromJson("{\"name\": \"Cheeseburger\"}", Burger::class.java) Gson() val gson = @zsmb13

Slide 37

Slide 37 text

data class Burger( val name: String, val price: Int ) Gson: missing data val burger = gson.fromJson("{\"name\": \"Cheeseburger\"}", Burger::class.java) Burger(name=Cheeseburger, price=0) Gson() val gson = @zsmb13

Slide 38

Slide 38 text

data class Burger( val name: String, val description: String ) val gson = Gson() Gson: missing data val burger = gson.fromJson("{\"name\": \"Cheeseburger\"}", Burger::class.java) @zsmb13

Slide 39

Slide 39 text

data class Burger( val name: String, val description: String ) val gson = Gson() Gson: missing data val burger = gson.fromJson("{\"name\": \"Cheeseburger\"}", Burger::class.java) Burger(name=Cheeseburger, description=null) @zsmb13

Slide 40

Slide 40 text

data class Burger( val name: String, val description: String = "One of our best burgers!" ) val gson = Gson() Gson: missing data val burger = gson.fromJson("{\"name\": \"Cheeseburger\"}", Burger::class.java) @zsmb13

Slide 41

Slide 41 text

data class Burger( val name: String, val description: String = "One of our best burgers!" ) val gson = Gson() Gson: missing data val burger = gson.fromJson("{\"name\": \"Cheeseburger\"}", Burger::class.java) Burger(name=Cheeseburger, description=null) @zsmb13

Slide 42

Slide 42 text

val gson = Gson() Gson: malformed data @zsmb13

Slide 43

Slide 43 text

val gson = Gson() Gson: malformed data data class Burger(val name: String, val price: Int) data class Restaurant(val menu: List) @zsmb13

Slide 44

Slide 44 text

val gson = Gson() Gson: malformed data data class Burger(val name: String, val price: Int) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" @zsmb13

Slide 45

Slide 45 text

val gson = Gson() Gson: malformed data data class Burger(val name: String, val price: Int) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" @zsmb13

Slide 46

Slide 46 text

val gson = Gson() Gson: malformed data data class Burger(val name: String, val price: Int) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" val restaurant = gson.fromJson(json, Restaurant::class.java) @zsmb13

Slide 47

Slide 47 text

Gson: malformed data val gson = Gson() data class Burger(val name: String, val price: Int) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" val restaurant = gson.fromJson(json, Restaurant::class.java) Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "crocodile" @zsmb13

Slide 48

Slide 48 text

val gson = Gson() Gson: malformed data data class Burger(val name: String, val price: Int) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" val restaurant = gson.fromJson(json, Restaurant::class.java) Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "crocodile" @zsmb13

Slide 49

Slide 49 text

val gson = Gson() Gson: malformed data data class Burger(val name: String, val price: Int) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "" } ] }""" val restaurant = gson.fromJson(json, Restaurant::class.java) Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "" @zsmb13

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

Say “hi” to zsmb.co zsmb13 Márton Braun Moshi

Slide 52

Slide 52 text

Moshi github.com/square/moshi @zsmb13

Slide 53

Slide 53 text

Okio github.com/square/okio Retrofit github.com/square/retrofit Moshi github.com/square/moshi OkHttp github.com/square/okhttp @zsmb13

Slide 54

Slide 54 text

Moshi github.com/square/moshi @zsmb13

Slide 55

Slide 55 text

Moshi 101 @zsmb13

Slide 56

Slide 56 text

Moshi 101 def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" @zsmb13

Slide 57

Slide 57 text

public JavaBurger(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } Moshi 101 } public class JavaBurger { private String name; private int price; @zsmb13

Slide 58

Slide 58 text

// ... public JavaBurger(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } Moshi 101 } public class JavaBurger { private String name; private int price; @zsmb13

Slide 59

Slide 59 text

// ... public JavaBurger(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } Moshi 101 val moshi = Moshi.Builder().build() } public class JavaBurger { private String name; private int price; @zsmb13

Slide 60

Slide 60 text

// ... public JavaBurger(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } Moshi 101 val moshi = Moshi.Builder().build() val json = moshi.toJson(JavaBurger("Classic", 10)) } public class JavaBurger { private String name; private int price; @zsmb13

Slide 61

Slide 61 text

// ... Moshi 101 val moshi = Moshi.Builder().build() val json = moshi.toJson(JavaBurger("Classic", 10)) } public class JavaBurger { private String name; private int price; @zsmb13

Slide 62

Slide 62 text

// ... Moshi 101 val moshi = Moshi.Builder().build() val json = moshi.toJson(JavaBurger("Classic", 10)) } public class JavaBurger { private String name; private int price; val burgerAdapter: JsonAdapter = moshi.adapter(JavaBurger::class.java) @zsmb13

Slide 63

Slide 63 text

// ... Moshi 101 val moshi = Moshi.Builder().build() } public class JavaBurger { private String name; private int price; val burgerAdapter: JsonAdapter = moshi.adapter(JavaBurger::class.java) val json = burgerAdapter.toJson(JavaBurger("Classic", 10)) @zsmb13

Slide 64

Slide 64 text

// ... Moshi 101 val moshi = Moshi.Builder().build() } public class JavaBurger { private String name; private int price; val burgerAdapter: JsonAdapter = moshi.adapter(JavaBurger::class.java) val json = burgerAdapter.toJson(JavaBurger("Classic", 10)) {"name":"Classic","price":10} @zsmb13

Slide 65

Slide 65 text

// ... Moshi 101 val moshi = Moshi.Builder().build() } public class JavaBurger { private String name; private int price; val burgerAdapter: JsonAdapter = moshi.adapter(JavaBurger::class.java) val json = burgerAdapter.toJson(JavaBurger("Classic", 10)) {"name":"Classic","price":10} val burger = burgerAdapter.fromJson(json) @zsmb13

Slide 66

Slide 66 text

Burger::class.java) // ... val moshi = Moshi.Builder().build() } public Java { private String ; private int ; Java val json = burgerAdapter.toJson(JavaBurger("Classic", 10)) {"name":"Classic","price":10} val burger = burgerAdapter.fromJson(json) Burger class val burgerAdapter: JsonAdapter< Burger> = moshi.adapter(Java name price @zsmb13 Moshi 101

Slide 67

Slide 67 text

Burger::class.java) val moshi = Moshi.Builder().build() (val : String, val : Int) val burgerAdapter: JsonAdapter = moshi.adapter( Burger class name price @zsmb13 Moshi ft. Kotlin

Slide 68

Slide 68 text

Burger::class.java) val moshi = Moshi.Builder().build() (val : String, val : Int) val burgerAdapter: JsonAdapter = moshi.adapter( Burger class name price Moshi ft. Kotlin Exception in thread "main" java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.example.Burger. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin- codegen artifact. @zsmb13

Slide 69

Slide 69 text

Moshi ft. Kotlin val moshi = Moshi.Builder().build() val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) Exception in thread "main" java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.example.Burger. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin- codegen artifact. @zsmb13

Slide 70

Slide 70 text

Moshi ft. Kotlin val moshi = Moshi.Builder().build() val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) Exception in thread "main" java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.example.Burger. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin- codegen artifact. @zsmb13

Slide 71

Slide 71 text

val moshi = Moshi.Builder().build() val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) Moshi ft. Kotlin Exception in thread "main" java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.example.Burger. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin- codegen artifact. @zsmb13

Slide 72

Slide 72 text

val moshi = Moshi.Builder().build() val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" @zsmb13 Moshi: reflection

Slide 73

Slide 73 text

val moshi = Moshi.Builder().build() Moshi: reflection val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" @zsmb13

Slide 74

Slide 74 text

val moshi = Moshi.Builder() Moshi: reflection val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) .build() @zsmb13

Slide 75

Slide 75 text

Moshi: reflection .add(KotlinJsonAdapterFactory()) val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) .build() val moshi = Moshi.Builder() @zsmb13

Slide 76

Slide 76 text

Moshi: reflection .add(KotlinJsonAdapterFactory()) val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) val json = burgerAdapter.toJson(Burger("Classic", 10)) .build() val moshi = Moshi.Builder() @zsmb13

Slide 77

Slide 77 text

Moshi: reflection .add(KotlinJsonAdapterFactory()) val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) val json = burgerAdapter.toJson(Burger("Classic", 10)) .build() val moshi = Moshi.Builder() @zsmb13 {"name":"Classic","price":10}

Slide 78

Slide 78 text

Moshi: reflection .add(KotlinJsonAdapterFactory()) val burgerAdapter: JsonAdapter = moshi.adapter(Burger::class.java) class Burger(val name: String, val price: Int) val json = burgerAdapter.toJson(Burger("Classic", 10)) .build() val moshi = Moshi.Builder() @zsmb13 {"name":"Classic","price":10} val burger = burgerAdapter.fromJson(json)

Slide 79

Slide 79 text

Moshi: reflection def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" @zsmb13

Slide 80

Slide 80 text

Moshi: reflection def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" Exception in thread "main" java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.example.Burger. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin- codegen artifact. @zsmb13

Slide 81

Slide 81 text

implementation moshi-kotlin:$moshi_version" "com.squareup.moshi: def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" Moshi: reflection Exception in thread "main" java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.example.Burger. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the artifact. moshi-kotlin- @zsmb13 codegen

Slide 82

Slide 82 text

def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" kapt moshi-kotlin-codegen:$moshi_version" "com.squareup.moshi: @zsmb13 Moshi: codegen

Slide 83

Slide 83 text

Moshi: codegen def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" @zsmb13

Slide 84

Slide 84 text

dependencies { } Moshi: codegen apply plugin: 'kotlin' apply plugin: 'kotlin-kapt' def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" @zsmb13

Slide 85

Slide 85 text

Moshi: codegen class Burger(val name: String, val price: Int) @zsmb13

Slide 86

Slide 86 text

@JsonClass(generateAdapter = true) class Burger(val name: String, val price: Int) @zsmb13 Moshi: codegen

Slide 87

Slide 87 text

@JsonClass(generateAdapter = true) class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val json = burgerAdapter.toJson(Burger("Double", 18))) @zsmb13 Moshi: codegen

Slide 88

Slide 88 text

dependencies { def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" } apply plugin: 'kotlin' apply plugin: 'kotlin-kapt' val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .build() @zsmb13 Moshi: mixed use

Slide 89

Slide 89 text

Moshi: mixed use dependencies { def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" } apply plugin: 'kotlin' apply plugin: 'kotlin-kapt' val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .build() @zsmb13

Slide 90

Slide 90 text

dependencies { def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" } apply plugin: 'kotlin' apply plugin: 'kotlin-kapt' val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .build() @zsmb13 Moshi: mixed use

Slide 91

Slide 91 text

class CustomBurgerAdapter { TODO("Implement deserialization") @ToJson fun toJson(writer: JsonWriter, value: Burger?) { TODO("Implement serialization") } } @FromJson fun fromJson(reader: JsonReader): Burger? { } @zsmb13 Moshi: custom adapters

Slide 92

Slide 92 text

@FromJson fun fromJson(reader: JsonReader): Burger? { } @zsmb13 Moshi: custom adapters

Slide 93

Slide 93 text

Moshi: custom adapters @FromJson fun fromJson(reader: JsonReader): Burger? { var name: String? = null var price: Int? = null } @zsmb13

Slide 94

Slide 94 text

Moshi: custom adapters @FromJson fun fromJson(reader: JsonReader): Burger? { var name: String? = null var price: Int? = null reader.beginObject() reader.endObject() } @zsmb13

Slide 95

Slide 95 text

Moshi: custom adapters @FromJson fun fromJson(reader: JsonReader): Burger? { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { } reader.endObject() } @zsmb13

Slide 96

Slide 96 text

Moshi: custom adapters @FromJson fun fromJson(reader: JsonReader): Burger? { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.nextName()) { "name" -> name = reader.nextString() "price" -> price = reader.nextInt() else -> reader.skipValue() } } reader.endObject() } @zsmb13

Slide 97

Slide 97 text

@FromJson fun fromJson(reader: JsonReader): Burger? { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.nextName()) { "name" -> name = reader.nextString() "price" -> price = reader.nextInt() else -> reader.skipValue() } } reader.endObject() return Burger(name!!, price!!) } @zsmb13 : custom adapters Moshi

Slide 98

Slide 98 text

class BurgerJsonAdapter( moshi: Moshi ) : JsonAdapter() { override fun toString(): String = buildString(28) { append("GeneratedJsonAdapter(").append("Burger").append(')') } private val options: JsonReader.Options = JsonReader.Options.of("name", "price") private val stringAdapter: JsonAdapter = moshi.adapter(String::class.java, emptySet(), "name") private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() return Burger( name = name ?: throw Util.missingProperty("name", "name", reader), price = price ?: throw Util.missingProperty("price", "price", reader) ) } override fun toJson(writer: JsonWriter, value: Burger?) { if (value == null) { throw NullPointerException( "value was null! Wrap in .nullSafe() to write nullable values.") } writer.beginObject() writer.name("name") stringAdapter.toJson(writer, value.name) writer.name("price") intAdapter.toJson(writer, value.price) writer.endObject() } } @zsmb13 Moshi’s generated adapter

Slide 99

Slide 99 text

class BurgerJsonAdapter( moshi: Moshi ) : JsonAdapter() { override fun toString(): String = buildString(28) { append("GeneratedJsonAdapter(").append("Burger").append(')') } private val options: JsonReader.Options = JsonReader.Options.of("name", "price") private val stringAdapter: JsonAdapter = moshi.adapter(String::class.java, emptySet(), "name") private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") @zsmb13 Moshi’s generated adapter

Slide 100

Slide 100 text

class BurgerJsonAdapter( moshi: Moshi ) : JsonAdapter() { override fun toString(): String = buildString(28) { append("GeneratedJsonAdapter(").append("Burger").append(')') } private val options: JsonReader.Options = JsonReader.Options.of("name", "price") private val stringAdapter: JsonAdapter = moshi.adapter(String::class.java, emptySet(), "name") private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") Moshi’s generated adapter @zsmb13

Slide 101

Slide 101 text

private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() Moshi’s generated adapter @zsmb13

Slide 102

Slide 102 text

private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() Moshi’s generated adapter @zsmb13

Slide 103

Slide 103 text

private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() Moshi’s generated adapter @zsmb13

Slide 104

Slide 104 text

private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() Moshi’s generated adapter @zsmb13

Slide 105

Slide 105 text

private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() Moshi’s generated adapter @zsmb13

Slide 106

Slide 106 text

override fun toString(): String = buildString(28) { append("GeneratedJsonAdapter(").append("Burger").append(')') } private val options: JsonReader.Options = JsonReader.Options.of("name", "price") private val stringAdapter: JsonAdapter = moshi.adapter(String::class.java, emptySet(), "name") private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) Moshi’s generated adapter @zsmb13

Slide 107

Slide 107 text

private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() Moshi’s generated adapter @zsmb13

Slide 108

Slide 108 text

private val options: JsonReader.Options = JsonReader.Options.of("name", "price") private val stringAdapter: JsonAdapter = moshi.adapter(String::class.java, emptySet(), "name") private val intAdapter: JsonAdapter = moshi.adapter(Int::class.java, emptySet(), "price") override fun fromJson(reader: JsonReader): Burger { var name: String? = null var price: Int? = null reader.beginObject() while (reader.hasNext()) { when (reader.selectName(options)) { 0 -> name = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("name", "name", reader) 1 -> price = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull("price", "price", reader) -1 -> { Moshi’s generated adapter @zsmb13

Slide 109

Slide 109 text

throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() return Burger( name = name ?: throw Util.missingProperty("name", "name", reader), price = price ?: throw Util.missingProperty("price", "price", reader) ) } } Moshi’s generated adapter @zsmb13

Slide 110

Slide 110 text

throw Util.unexpectedNull("price", "price", reader) -1 -> { reader.skipName() reader.skipValue() } } } reader.endObject() return Burger( name = name ?: throw Util.missingProperty("name", "name", reader), price = price ?: throw Util.missingProperty("price", "price", reader) ) } } @zsmb13 Moshi’s generated adapter

Slide 111

Slide 111 text

val moshi = Moshi.Builder().build() val adapter: JsonAdapter = moshi.adapter(Date::class.java) @zsmb13 : built-in types Moshi

Slide 112

Slide 112 text

val moshi = Moshi.Builder().build() val adapter: JsonAdapter = moshi.adapter(Date::class.java) @zsmb13 Moshi: built-in types

Slide 113

Slide 113 text

Moshi: built-in types val moshi = Moshi.Builder().build() val adapter: JsonAdapter = moshi.adapter(Date::class.java) Exception in thread "main" java.lang.IllegalArgumentException: Platform class java.util.Date requires explicit JsonAdapter to be registered @zsmb13

Slide 114

Slide 114 text

Moshi: built-in types def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" val moshi = Moshi.Builder().build() val adapter: JsonAdapter = moshi.adapter(Date::class.java) @zsmb13

Slide 115

Slide 115 text

Moshi: built-in types def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" implementation "com.squareup.moshi:moshi-adapters:$moshi_version" val moshi = Moshi.Builder().build() val adapter: JsonAdapter = moshi.adapter(Date::class.java) @zsmb13

Slide 116

Slide 116 text

def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-adapters:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" val adapter: JsonAdapter = moshi.adapter(Date::class.java) .build() val moshi = Moshi.Builder() @zsmb13 Moshi: built-in types

Slide 117

Slide 117 text

val adapter: JsonAdapter = moshi.adapter(Date::class.java) def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-adapters:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" .add(Date::class.java, Rfc3339DateJsonAdapter()) .build() val moshi = Moshi.Builder() @zsmb13 Moshi: built-in types 2021-10-29T : : Z 21 22 13

Slide 118

Slide 118 text

val adapter: JsonAdapter = moshi.adapter(Date::class.java) def moshi_version = '1.12.0' implementation "com.squareup.moshi:moshi:$moshi_version" implementation "com.squareup.moshi:moshi-adapters:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" .add(Date::class.java, Rfc3339DateJsonAdapter()) 2021-10-29T : : Z .build() val moshi = Moshi.Builder() @zsmb13 Moshi: built-in types 21 22 22

Slide 119

Slide 119 text

@zsmb13 Moshi: field naming

Slide 120

Slide 120 text

@JsonClass(generateAdapter = true) data class Burger( @Json(name = "name") val name: String, @Json(name = "total_cost") val totalCost: Int, @Json(name = "sales_price") val salesPrice: Int ) @zsmb13 Moshi: field naming

Slide 121

Slide 121 text

@JsonClass(generateAdapter = true) data class Burger( @Json(name = "name") val name: String, @Json(name = "total_cost") val totalCost: Int, @Json(name = "sales_price") val salesPrice: Int ) moshi.adapter(Burger::class.java) .toJson(Burger("Classic", 10, 13)) @zsmb13 Moshi: field naming

Slide 122

Slide 122 text

@JsonClass(generateAdapter = true) data class Burger( @Json(name = "name") val name: String, @Json(name = "total_cost") val totalCost: Int, @Json(name = "sales_price") val salesPrice: Int ) moshi.adapter(Burger::class.java) .toJson(Burger("Classic", 10, 13)) {"name":"Classic","total_cost":10,"sales_price":13} @zsmb13 Moshi: field naming

Slide 123

Slide 123 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val total_cost: Int, val sales_price: Int ) moshi.adapter(Burger::class.java) .toJson(Burger("Classic", 10, 13)) {"name":"Classic","total_cost":10,"sales_price":13} @zsmb13 Moshi: field naming

Slide 124

Slide 124 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val price: Int ) @zsmb13 Moshi: missing data

Slide 125

Slide 125 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val price: Int ) Moshi: missing data @zsmb13

Slide 126

Slide 126 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val price: Int ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) @zsmb13

Slide 127

Slide 127 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val price: Int ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) Exception in thread "main" com.squareup.moshi.JsonDataException: Required value 'price' missing at $ @zsmb13

Slide 128

Slide 128 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val description: String ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) @zsmb13

Slide 129

Slide 129 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val description: String ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) @zsmb13

Slide 130

Slide 130 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val description: String ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) Exception in thread "main" com.squareup.moshi.JsonDataException: Required value 'description' missing at $ @zsmb13

Slide 131

Slide 131 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val description: String? ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) @zsmb13

Slide 132

Slide 132 text

@JsonClass(generateAdapter = true) data class Burger( val name: String, val description: String? ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) Burger(name=Cheeseburger, description=null) @zsmb13

Slide 133

Slide 133 text

Burger(name=Cheeseburger, description=null) @JsonClass(generateAdapter = true) data class Burger( val name: String, val description: String = "One of our best burgers!" ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) @zsmb13

Slide 134

Slide 134 text

Burger(name=Cheeseburger, description=null) @JsonClass(generateAdapter = true) data class Burger( val name: String, val description: String = "One of our best burgers!" ) Moshi: missing data val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\"}" ) Burger(name=Cheeseburger, description=One of our best burgers!) @zsmb13

Slide 135

Slide 135 text

val moshi = Moshi.Builder() Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) .build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\", \"price\": 13}" ) @zsmb13

Slide 136

Slide 136 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) .add(...) val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\", \"price\": 13}" ) .build() val moshi = Moshi.Builder() @zsmb13

Slide 137

Slide 137 text

val moshi = Moshi.Builder() Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) .build() val burgerAdapter = moshi.adapter(Burger::class.java) val burger = burgerAdapter.fromJson( "{\"name\": \"Cheeseburger\", \"price\": 13}" ) @zsmb13

Slide 138

Slide 138 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) JsonAdapter @zsmb13

Slide 139

Slide 139 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) @zsmb13

Slide 140

Slide 140 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int?) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) @zsmb13

Slide 141

Slide 141 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int?) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.toJson(Burger("Cancelled", null)) @zsmb13

Slide 142

Slide 142 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int?) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.toJson(Burger("Cancelled", null)) {"name":"Cancelled"} @zsmb13

Slide 143

Slide 143 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int?) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .serializeNulls() burgerAdapter.toJson(Burger("Cancelled", null)) {"name":"Cancelled","price":null} @zsmb13

Slide 144

Slide 144 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int?) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .serializeNulls() burgerAdapter.toJson(Burger("Cancelled", null)) {"name":"Cancelled","price":null} @zsmb13 JsonAdapter

Slide 145

Slide 145 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int?) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .serializeNulls() burgerAdapter.toJson(Burger("Cancelled", null)) {"name":"Cancelled","price":null} @zsmb13

Slide 146

Slide 146 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.toJson(null) @zsmb13

Slide 147

Slide 147 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.toJson(null) null @zsmb13

Slide 148

Slide 148 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .nullSafe() burgerAdapter.toJson(null) null @zsmb13

Slide 149

Slide 149 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .nonNull() burgerAdapter.toJson(null) @zsmb13

Slide 150

Slide 150 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .nonNull() burgerAdapter.toJson(null) Exception in thread "main" com.squareup.moshi.JsonDataException: Unexpected null at $ @zsmb13

Slide 151

Slide 151 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) @zsmb13

Slide 152

Slide 152 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.fromJson( "{\"name\":\"Cheeseburger\",\"price\": 13}" ) @zsmb13

Slide 153

Slide 153 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.fromJson( "{\"name\":\"Cheeseburger\",\"price\": 13}" ) Burger(name=Cheeseburger, price=13) @zsmb13

Slide 154

Slide 154 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.fromJson( "{\"name\":\"Cheeseburger\",\"price\": 13,\"rating\":4.2}" ) @zsmb13

Slide 155

Slide 155 text

Moshi: customization options @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) burgerAdapter.fromJson( "{\"name\":\"Cheeseburger\",\"price\": 13,\"rating\":4.2}" ) Burger(name=Cheeseburger, price=13) @zsmb13

Slide 156

Slide 156 text

@JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .failOnUnknown() burgerAdapter.fromJson( "{\"name\":\"Cheeseburger\",\"price\": 13,\"rating\":4.2}" ) Moshi: customization options @zsmb13

Slide 157

Slide 157 text

@JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) val moshi = Moshi.Builder().build() val burgerAdapter = moshi.adapter(Burger::class.java) .failOnUnknown() burgerAdapter.fromJson( "{\"name\":\"Cheeseburger\",\"price\": 13,\"rating\":4.2}" ) Moshi: customization options Exception in thread "main" com.squareup.moshi.JsonDataException: Cannot skip unexpected NAME at $.rating @zsmb13

Slide 158

Slide 158 text

Moshi: malformed data @zsmb13

Slide 159

Slide 159 text

@JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) @zsmb13 Moshi: malformed data

Slide 160

Slide 160 text

@JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" @zsmb13 Moshi: malformed data

Slide 161

Slide 161 text

@JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" val restaurant = adapter.fromJson(json, Restaurant::class.java) @zsmb13 Moshi: malformed data

Slide 162

Slide 162 text

Moshi: malformed data @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" val restaurant = adapter.fromJson(json, Restaurant::class.java) Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price @zsmb13

Slide 163

Slide 163 text

val json = val restaurant = adapter.fromJson(json, Restaurant::class.java) """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" Moshi: malformed data @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price @zsmb13

Slide 164

Slide 164 text

"""{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price @zsmb13

Slide 165

Slide 165 text

Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" @zsmb13

Slide 166

Slide 166 text

Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" @zsmb13

Slide 167

Slide 167 text

Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" @zsmb13

Slide 168

Slide 168 text

Moshi: malformed data @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = val restaurant = adapter.fromJson(json, Restaurant::class.java) """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price @zsmb13

Slide 169

Slide 169 text

Moshi: malformed data @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = val restaurant = adapter.fromJson(json, Restaurant::class.java) """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "crocodile" @zsmb13

Slide 170

Slide 170 text

Moshi: malformed data @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = val restaurant = adapter.fromJson(json, Restaurant::class.java) """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "crocodile" } ] }""" Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was crocodile at path $.menu[2].price Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "crocodile" @zsmb13

Slide 171

Slide 171 text

Moshi: malformed data @JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = val restaurant = adapter.fromJson(json, Restaurant::class.java) """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "" } ] }""" Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was at path $.menu[2].price Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "" @zsmb13

Slide 172

Slide 172 text

@JsonClass(generateAdapter = true) data class Burger(val name: String, val price: Int) @JsonClass(generateAdapter = true) data class Restaurant(val menu: List) val json = val restaurant = adapter.fromJson(json, Restaurant::class.java) """{ "menu": [ { "name": "Classic", "price": 10 }, { "name": "Cheeseburger", "price": 13 }, { "name": "Double", "price": "" } ] }""" Moshi: malformed data Exception in thread "main" com.squareup.moshi.JsonDataException: Expected an int but was at path $.menu[2].price Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "" @zsmb13

Slide 173

Slide 173 text

def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" @zsmb13 Moshi: Retrofit integration

Slide 174

Slide 174 text

def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" @zsmb13 Moshi: Retrofit integration

Slide 175

Slide 175 text

Retrofit.Builder() .baseUrl("...") .addConverterFactory(MoshiConverterFactory.create()) .build() def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" @zsmb13 Moshi: Retrofit integration

Slide 176

Slide 176 text

Retrofit.Builder() .baseUrl("...") .addConverterFactory(MoshiConverterFactory.create()) .build() def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .add(...) .build() @zsmb13 Moshi: Retrofit integration

Slide 177

Slide 177 text

def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .add(...) .build() @zsmb13 Moshi: Retrofit integration )) Retrofit.Builder() .baseUrl("...") .addConverterFactory(MoshiConverterFactory.create( .build()

Slide 178

Slide 178 text

Retrofit.Builder() .baseUrl("...") .addConverterFactory(MoshiConverterFactory.create( .build() def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .add(...) .build() @zsmb13 Moshi: Retrofit integration )) moshi

Slide 179

Slide 179 text

More Moshi… •Other built-in adapters •Intermediate objects while parsing •Annotated types •Parsing arrays and other generic types •KSP support •A lot more under-the-hood details! @zsmb13

Slide 180

Slide 180 text

Resources •A Few Ok Libraries (Jake Wharton, Square) – Droidcon Montreal 2015 • https://www.youtube.com/watch?v=WvyScM_S88c •Upgrading to Moshi (Eric Cochran, Pinterest) - droidcon NYC 2017 • https://www.youtube.com/watch?v=xHFs7cccnXU •JSON Explained (Jesse Wilson, Square) – Chicago Roboto 2019 • https://www.youtube.com/watch?v=1PwdqkKDCSo @zsmb13

Slide 181

Slide 181 text

Resources •Moshi, another JSON Processor (Jesse Wilson) • https://developer.squareup.com/blog/moshi-another-json-processor/ •Exploring Moshi’s codegen (Zac Sweers) • https://www.zacsweers.dev/exploring-moshis-kotlin-code-gen/ •Reflection Machines (Jesse Wilson) • https://publicobject.com/2016/03/24/reflection-machines/ •Advanced JSON parsing techniques using Moshi and Kotlin (Christophe Beyls) • https://medium.com/@BladeCoder/advanced-json-parsing-techniques- using-moshi-and-kotlin-daf56a7b963d @zsmb13

Slide 182

Slide 182 text

zsmb.co/talks zsmb13 Márton Braun › Reflection or codegen › Kotlin-friendly › Really fast › Great failure modes › Neat APIs Say “hi” to Moshi