1. soranakk

    Posted

    soranakk
Changes in title
+moshi-adapters
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,137 @@
+# Moshi-adapters
+
+Moshi-adaptersはMoshiのアドオンライブラリです。
+
+# Moshi
+
+MoshiはKotlinでJsonを扱うライブラリです。
+標準的なデータ型とjsonの相互変換をサポートしています。
+
+* int, float, charなどのプリミティブ型および、それらのオブジェクト型(Integer, Float, Character)
+* Arrays, List, Mapなど
+* String
+* Enum
+
+# Moshi-codegen
+
+Moshiでサポートしていない型(自作Classなど)を扱うときにはAdapterを作成する必要があります。
+ですが、それをannotation processorで生成してくれるライブラリがMoshi-codegenです。
+Moshi-codegenはMoshi公式からリリースされています。
+
+以下のように変換したいクラスにアノテーションをつけることでAdapterが自動生成されます。
+これはKotlinのdata classも対象にできます。
+
+```Kotlin
+@JsonClass(generateAdapter = true)
+class Item(val name: String)
+
+@JsonClass(generateAdapter = true)
+data class Cart(val items: List<Item>)
+
+val adapter = Moshi.Builder().build().adapter(Cart::class.java)
+
+val cart = Cart(items = listOf(Item("りんご"), Item("電球")))
+val jsonString = adapter.toJson(cart)
+println(jsonString) // {"items":[{"name":"りんご"},{"name":"電球"}]}
+```
+
+# Moshi-adapters
+
+ようやく本題のMoshi-adaptersです。
+これはいくつかのAdapterを追加するライブラリです。
+現在(ver 1.8.0)では時刻に関するAdapterとEnumに関するAdapter、継承したクラスのAdapterがあります。
+
+## EnumJsonAdapter
+
+MoshiはもともとEnumとjsonの相互変換に対応しています。
+
+```Kotlin
+enum class Type {
+ A,B,UNKNOWN
+}
+val adapter = Moshi.Builder().build().adapter(Type::class.java)
+
+val type = Type.A
+val jsonString = adapter.toJson(type)
+println(jsonString) // "A"
+```
+
+しかし、知らないStringが来たときはEnumにマップできず例外が投げられます。
+
+```Kotlin
+val fromJson = try {
+ adapter.fromJson("\"C\"")
+} catch (e: Exception) {
+ null
+}
+println("fromJson:$fromJson") // fromJson:null
+```
+
+CというEnumは定義されていないので例外が発生して`fromJson`は`null`になってしまいます。
+EnumJsonAdapterは知らないStringが来たときのデフォルト値を設定するためのAdapterです。
+使い方を見ましょう。
+
+```Kotlin
+val adapter = Moshi.Builder()
+ .add(Type::class.java,
+ EnumJsonAdapter.create(Type::class.java).withUnknownFallback(Type.UNKNOWN))
+ .build().adapter(Type::class.java)
+
+val fromJson = try {
+ adapter.fromJson("\"C\"")
+} catch (e: Exception) {
+ null
+}
+println("fromJson:$fromJson") // fromJson:UNKNOWN
+```
+
+このように、未知の値がCがやってきたので`withUnknownFallback`で指定した`UNKNOWN`に変換されました。
+
+## PolymorphicJsonAdapterFactory
+
+あるスーパークラスがあって、それを継承したクラスのjson変換をしたい場合に利用します。
+これを使うと、継承したクラスをjsonへシリアライズすることも、jsonからデシリアライズすることもできるようになります。
+例を見ましょう。
+
+```Kotlin
+sealed class SealedItem(val name: String) {
+ @JsonClass(generateAdapter = true)
+ class Food(name:String) : SealedItem(name)
+
+ @JsonClass(generateAdapter = true)
+ class Appliances(name:String) : SealedItem(name)
+}
+
+@JsonClass(generateAdapter = true)
+data class SealedCart(val items: List<SealedItem>)
+```
+
+このように、SealedItemというクラスがあって、それを継承したFoodとAppliancesがあったとします。
+これをjsonに変換したり、jsonから戻したりするときに利用するのがPolymorphicJsonAdapterFactoryです。
+使い方を見ましょう。
+
+```Kotlin
+val cart = SealedCart(items = listOf(SealedItem.Food("りんご"),
+ SealedItem.Appliances("電球")))
+
+val adapter = Moshi.Builder()
+ .add(PolymorphicJsonAdapterFactory.of(SealedItem::class.java, "type")
+ .withSubtype(SealedItem.Food::class.java, "food")
+ .withSubtype(SealedItem.Appliances::class.java, "appliances"))
+ .build().adapter(SealedCart::class.java)
+
+val jsonString = adapter.toJson(cart)
+val fromJson = adapter.fromJson(jsonString)
+
+println(jsonString)
+// {"items":[{"type":"food","name":"SealedItem"},{"type":"appliances","name":"電球"}]}
+```
+
+このように、json変換したときに`of`で指定したプロパティが追加され、そのプロパティに`withSubtype`で型毎に指定した値がセットされるようになります。
+これを使ってjson変換してくれるAdapterを生成できるのがPolymorphicJsonAdapterFactoryです。
+
+# まとめ
+
+Moshiを利用しているなら、ぜひMoshi-adaptersも利用しましょう!
+
+