Kotlinにも対応したJSONライブラリーMoshiの基本的な使い方

# 検証環境
この記事の内容は、以下の環境で検証しました。

* Intellij IDEA ULTIMATE 2017.3
* Kotlin 1.2
* Java 1.8
* Moshi 1.5.0
* Gradle Projectで作成

# 目標
Moshiの利用方法を理解する。

具体的には以下を理解する。
* JSONをパースして、データクラスのオブジェクトを生成
* データクラスからJSONの生成

# Moshiとは

Moshiとは、JavaやAndroid向けのモダンなJSONライブラリーです。
また、JSONからJavaのオブジェクトへの変換が簡単に行なえます。

https://github.com/square/moshi

# 準備
Moshiを使用するため、Gradleに以下の１行を追記します。

```groovy
    compile 'com.squareup.moshi:moshi-kotlin:1.5.0'
```

# 事前準備
本記事とは直接関係ないですが、サンプルで使用しているクラスを事前に説明しておきます。

## Userデータクラス
JSONからオブジェクトやオブジェクトからJSONにパースする際に使用するクラスです。

```kotlin
data class User(val name:String,val detail:UserDetail)
```
## UserDeatailデータクラス
Userクラスのプロパティとして保持するクラスです。

```kotlin
data class UserDetail(val age:Int, val job:String)
```

## createUser関数
Userデータクラスで、サンプルデータを保持したオブジェクトを生成する関数です。

```kotlin
fun  createUser():User{
    return User("山田太郎",UserDetail(25,"会社員"));
}
```
## createMultiUser関数
Userデータクラスのオブジェクトを格納したList型のオブジェクトを生成する関数です。

```kotlin
fun createMultiUser(): List<User> {

    return listOf<User>(User("福沢諭吉",UserDetail(66,"偉人")),
            User("樋口一葉",UserDetail(24,"作家")),
            User("野口英世",UserDetail(51,"医師")))
}
```


# 実装例

## クラス→JSON変換

### コード例
オブジェクトをJSONに変換するコードは、以下のとおりです。

```kotlin
    val user = createUser()

    // クラス→JSON変換
    val moshi = Moshi.Builder().build()
    val adapter = moshi.adapter(User::class.java)
    val decodeJson = adapter.toJson(user)

    println("クラス→JSON：${decodeJson}")
```

### 解説
Moshiを使用するには、Moshiのオブジェクトが必要です。そのオブジェクトを生成するには、MoshiのBuilderクラスを使用し、builderメソッドを呼び出します。

```kotlin
 val moshi = Moshi.Builder().build()
```

adapterメソッドで、変換するクラス情報をMoshiに渡します。
戻り値として、JsonAdapter型のオブジェクトが帰ってきます。

```kotlin
    val adapter = moshi.adapter(User::class.java)
```

JsonAdapterクラスのtoJsonメソッドでJSONを生成します。

```kotlin
 val decodeJson = adapter.toJson(user)
```

### 実行結果

```json

クラス→JSON：{"detail":{"age":25,"job":"会社員"},"name":"山田太郎"}
```

## JSON→クラス変換
### コード例
JSONからオブジェクトに変換するコードは、以下のとおりです。

```kotlin
    // JSON→クラス変換
    val json = "{\"detail\":{\"age\":30,\"job\":\"自営業\"},\"name\":\"佐藤二朗\"}"

    val fromJson = adapter.fromJson(json)
    println("JSON→クラス：${fromJson}")
```

### 解説
パースするJSON文字列を準備しています。

```kotlin
val json = "{\"detail\":{\"age\":30,\"job\":\"自営業\"},\"name\":\"佐藤二朗\"}"
```

『クラス→JSON変換』で生成したJsonAdapterのfromJsonメソッドでパースします。

```kotlin
val fromJson = adapter.fromJson(json)
```
### 実行結果
実行結果は、以下の通りです。

```text
JSON→クラス：User(name=佐藤二朗, detail=UserDetail(age=30, job=自営業))
```
## リストに格納されたクラス→JSON

### コード例
オブジェクトを格納したリストをJSONに変換するコードは、以下のとおりです。

```kotlin
    val type = Types.newParameterizedType(List::class.java,User::class.java)
    val listAdapter:JsonAdapter<List<User>> = moshi.adapter(type)
    val multiUserJson = listAdapter.toJson(createMultiUser())

    println("リストに格納されたクラス→JSON:${multiUserJson}")
``` 

### 解説
List型などのコレクション型をJSON文字列にする際、Types.newParameterizedTypeメソッドでParameterizedTypeクラスのオブジェクトを生成します。
Moshiのadapterメソッドの引数にParameterizedTypeクラスのオブジェクトを渡すことにより、List型のJsonAdapterが生成できます。

```kotlin
    val type = Types.newParameterizedType(List::class.java,User::class.java)
    val listAdapter:JsonAdapter<List<User>> = moshi.adapter(type)
```

JSON文字列の生成は、これまでのadapter同様にtoJsonメソッドを呼び出します。

```kotlin
    val multiUserJson = listAdapter.toJson(createMultiUser())
```

### 実行結果
実行結果は、以下の通りです。

```json
リストに格納されたクラス→JSON:[{"detail":{"age":66,"job":"偉人"},"name":"福沢諭吉"},{"detail":{"age":24,"job":"作家"},"name":"樋口一葉"},{"detail":{"age":51,"job":"医師"},"name":"野口英世"}]
```

## JSON→リストに格納されたクラス

### コード例
JSON文字列からオブジェクトを格納したリストに変換するコードは、以下のとおりです。

```kotlin
    val file = File("src/main/resources/list_data.json")
    val fileContents = file.absoluteFile.bufferedReader().use { it.readText() }

    val listObject = listAdapter.fromJson(fileContents);
    println("JSON→リストに格納されたクラス:${listObject}")
```

### 解説

サンプルデータはファイルで用意したため、ファイルの読み込みを記述しています。

```kotlin
val file = File("src/main/resources/list_data.json")
val fileContents = file.absoluteFile.bufferedReader().use { it.readText() }
```
ちなみに、今回使用するJSON文字列は以下の通りです。

```json
[
  {
    "name": "佐藤一郎",
    "detail": {
      "age": 21,
      "job": "コック"
    }
  },
  {
    "name": "山田花子",
    "detail": {
      "age": 35,
      "job": "パティシエ"
    }
  },
  {
    "name": "木村二郎",
    "detail": {
      "age": 45,
      "job": "経営者"
    }
  }
]
```

adapterの生成方法は、『JSON→リストに格納されたクラス』と同じです。
adapterのfromJsonを呼び出すことに、List型の値が取得できます。

```kotlin
val listObject = listAdapter.fromJson(fileContents);
```

### 実行結果
実行結果は、以下の通りです。

```text
JSON→リストに格納されたクラス:[User(name=佐藤一郎, detail=UserDetail(age=21, job=コック)), User(name=山田花子, detail=UserDetail(age=35, job=パティシエ)), User(name=木村二郎, detail=UserDetail(age=45, job=経営者))]
```

# まとめ
世の中には様々なJSONのライブラリーが存在します。多くのライブラリーは、パース処理やJSON文字列変換処理を静的メソッドで定義しており、Adapterを生成する必要がありません。使い慣れるまで時間は掛かりそうですが、様々なカスタマイズが可能です。
いつか使い倒したい。