山下寛人オフィシャルブログ

オイシックス株式会社 執行役員 システム本部長 山下寛人の公式ブログです。

KotlinでスマートにJSONをさばく

KotlinでJSONを使う場合、言語そのものには機能がないのでライブラリを使うことになります。Javaのものも含め選択肢は多様です。JavaScriptと違いJavaやKotlinは型がしっかりしている言語なのでJSONマッピングするクラスをあらかじめ作っておいてそこに当てはめるようなものが多いようです。でもそれだとJSON自体はデータ形式はいろいろ柔軟に変えられますが受けるほうはそんなに柔軟にできません。またモックを作るときは余分なクラスを作らずさっと済ませたい場合もあります。こういうときMapやListベースでJSONを使えるとよいです。

Moshiというライブラリはそういった使い方ができます。しかし値を取ったらキャストしないとその中の値が取れずいまいちスマートにできませんでした。

map = map["grouped"] as Map<*, *>
map = map["category_name"] as Map<*, *>

一番よかったのはklaxonです。Kotlin用です。
github.com
使い方は

var obj = Parser.parse(JSONのストリーム)

こうするとArrayに相当するJsonArrayもしくはMapに相当するJsonObjectが返ってきます。

var productsDictionary = obj.lookup<JsonArray<String>>("grouped.category_name.doclist.docs.category_name")

こういった具合にlookupメソッドでJavaScript的に一発で中の方の値にアクセスできます。

注意すべき点としては日本語が文字化けします。内部ではUTF-8でも1バイトずつ処理していました。でもunicodeエスケープしておけば対応できるようになっていました。
unicodeエスケープというのは、\u9999みたいな形で文字を表現するやり方です。昔のJavaではプロパティファイルを作るときにnative2asciiコマンドを使ってこんなことをしたと思います。今時もうやりませんが・・
一番手軽なやり方はcommonsのStringEscapeUtilsを使う方法です。

jsonstr = StringEscapeUtils.escapeJava(jsonstr).replace("\\\"", "\"")

ダブルコーテーションの前にバックスラッシュがついてしまうのでreplaceコマンドで消しています。こうやって

var obj = Parser().parse(jsonstr.byteInputStream()) as JsonObject

として渡してやれば日本語も文字化けしません。

型がしっかりしたKotlinでもJavaScript並にすっきり書けました。なおかつflatMap,map,filterなど使ってスマートに処理できます。