検証環境
この記事の内容は、以下の環境で検証しました。
- Intellij IDEA ULTIMATE 2017.2
- Kotlin 1.1.61
- Fuel 1.12.0
- Moshi 1.5.0
- Java 1.8
- Gradle Projectで作成
目標
Fuelには、JSONライブラリーと連携する機能が備わっています。
本記事は、『FuelとMoshiの連携方法を理解する』を目標とします。
【連携可能なライブラリー】
- GSON
- Moshi
- Jackson
前提
下記の記事を理解していることを前提として、本記事を記述しています。
事前準備
本記事とは直接関係ないですが、サンプルで使用しているクラスを事前に説明しておきます。
Userデータクラス
JSONからオブジェクトやオブジェクトからJSONにパースする際に使用するクラスです。
data class User(val name:String,val detail:UserDetail)
UserDeatailデータクラス
Userクラスのプロパティとして保持するクラスです。
data class UserDetail(val age:Int, val job:String)
返ってくるJSON
今回サンプル用にローカルに用意したサーバで返すJSONは以下の通りです。
単一オブジェクトのJSON
URL
http://localhost:8080/userInfo
JSON
{"detail":{"age":25,"job":"会社員"},"name":"山田太郎"}
配列形式のJSON
URL
http://localhost:8080/multiUserInfo
[{"detail":{"age":66,"job":"偉人"},"name":"福沢諭吉"},{"detail":{"age":24,"job":"作家"},"name":"樋口一葉"},{"detail":{"age":51,"job":"医師"},"name":"野口英世"}]
実装例
単一オブジェクトのJSON
コード例
レスポンスのJSONをデータクラスに変換するコードは、以下の通りです。
"http://localhost:8080/userInfo".httpGet().responseObject<User> { req, res, result ->
val(user,err) = result
println("user:${user}");
}
解説
レスポンスで受け取ったデータを指定したデータクラスの型に変換するには、『responseObject関数』を使用します。
関数のジェネリクスにデータクラスのを指定するだけで変換します。
responseObject<User>
resultにUserデータクラスに変換したオブジェクトが格納されています。
今回は分解宣言で取得しています。userという変数にUserデータクラスのオブジェクトが格納されます。
val(user,err) = result
実行結果
user:User(name=山田太郎, detail=UserDetail(age=25, job=会社員))
配列形式のJSON
コード例
配列形式のJSONをUserデータクラスを格納したリストに変換するコードは、以下の通りです。
JSONをList型に変換する処理を記述したクラス
package jp.co.casareal.fuelmoshi
import com.github.kittinunf.fuel.core.ResponseDeserializable
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
class UserListDeserializer : ResponseDeserializable<List<User>> {
override fun deserialize(content: String): List<User>? {
val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(List::class.java, User::class.java)
val listAdapter: JsonAdapter<List<User>> = moshi.adapter(type)
return listAdapter.fromJson(content)
}
}
HTTP通信を行い、レスポンスをUserListDeserializerでList型に変換する処理
"http://localhost:8080/multiUserInfo".httpGet().responseObject(UserListDeserializer()) { req, res, result ->
val(list,err) = result
list?.forEach {
println(it)
}
}
解説
配列のJSONを受け取る場合は、responseObject関数のジェネリクスで指定しても、List型に正しく変換されません。
変換するには、ResponseDeserializableを継承し、deserializeメソッドとオーバライドしたクラスを用意する必要があります。
class UserListDeserializer : ResponseDeserializable<List<User>> {
override fun deserialize(content: String): List<User>? {
・・・省略・・・
}
}
deserializeメソッド内でJSONからオブジェクトに変換する処理を行います。
処理内容詳細は、下記の記事に記述しています。
https://casareal-ls.qiita.com/naoi/items/64413e2777210526aa87
val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(List::class.java, User::class.java)
val listAdapter: JsonAdapter<List<User>> = moshi.adapter(type)
return listAdapter.fromJson(content)
deserializeメソッドはオーバロードされており、引数の型を以下から選べます。
- public fun deserialize(bytes: ByteArray): T?
- public fun deserialize(inputStream: InputStream): T?
- public fun deserialize(reader: Reader): T?
- public fun deserialize(content: String): T?
HTTP通信は単一オブジェクトのJSONと同じようにresponseObject関数を利用します。
responseObject関数の引数にUserListDeserializerクラスのインスタンスを渡すことによって
作成したUserListDeserializerクラスのdeserializeメソッドが動作し、変換処理が行われます。
responseObject(UserListDeserializer())
以降は単一オブジェクトのJSONと同じ為、説明は省略します。
実行結果
User(name=福沢諭吉, detail=UserDetail(age=66, job=偉人))
User(name=樋口一葉, detail=UserDetail(age=24, job=作家))
User(name=野口英世, detail=UserDetail(age=51, job=医師))