はじめに
Moshi-adaptersはMoshiのアドオンライブラリです。
Moshi公式からリリースされています。
まずはMoshiって何?って方のために、簡単にMoshiの紹介から。
Moshi
MoshiはJavaでJsonを扱うためのライブラリです。
またMoshiはKotlinと相性が良く、Kotlinと一緒に利用されていることが多いです。
Json変換は標準的なデータ型とjsonとの相互変換をサポートしています。
- int, float, charなどのプリミティブ型および、それらのオブジェクト型(Integer, Float, Character)
- Arrays, List, Mapなど
- String
- Enum
Moshi-codegen
Moshi-codegenはKotlinでMoshiを利用するときに便利なライブラリです。
Moshiではサポートしていない型(自作Classなど)を扱うときにはAdapterを作成する必要があります。
ですが、Moshi-codegenはそれをannotation processorで生成してくれます。
Moshi-codegenはMoshi公式からリリースされています。
以下のように変換したいクラスにアノテーションをつけることでAdapterが自動生成されます。
これはKotlinのdata classも対象にできます。
@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を追加するライブラリです。
version 1.8.0では、時刻に関するAdapterとEnumに関するAdapter、継承したクラスのAdapterがあります。
EnumJsonAdapter
MoshiはもともとEnumとjsonの相互変換に対応しています。
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にマップできず例外が投げられます。
val fromJson = try {
adapter.fromJson("\"C\"")
} catch (e: Exception) {
null
}
println("fromJson:$fromJson") // fromJson:null
CというEnumは定義されていないので例外が発生してfromJson
はnull
になってしまいます。
新しいEnum値を追加したとき、古いコードではUNKNOWNにするなどして逃げたい、ということがありますよね。
そういう時に使うのがEnumJsonAdapterです。
EnumJsonAdapterはEnumで知らない値が来たときのデフォルト値を設定するためのAdapterです。
使い方を見ましょう。
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からデシリアライズすることもできるようになります。
例を見ましょう。
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です。
使い方を見ましょう。
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":"りんご"},{"type":"appliances","name":"電球"}]}
このように、json変換したときにof
で指定したプロパティが追加され、そのプロパティにwithSubtype
で型毎に指定した値がセットされるようになります。
このようにjson変換してくれるAdapterを生成できるのがPolymorphicJsonAdapterFactoryです。
まとめ
Moshiを利用しているなら、ぜひMoshi-adaptersも利用しましょう!