Scalaがとても楽しいので、spray-jsonによるScalaコード内でオブジェクトのjson変換を試してみました。
spray/spray-json · GitHub
基本的に上記のレポジトリのコードを元にしました。
ScalaのオブジェクトならDefaultJsonProtocolというトレイトを継承または、利用すれば変換することが出来るようです。
とても楽でした。
準備 /build.sbt
準備はbuild.sbtを以下のようにするだけです。
libraryDependencies += "io.spray" %% "spray-json" % "1.3.1"
一般的なScalaオブジェクトをjsonに変換する
上記の準備だけで、toJsonを利用して、Scalaのオブジェクトをjson化することが出来ます。
Scalaで用意されたオブジェクト(Listなど)の変換には2通りのやり方があります。
- 継承するパターン
- traitを使うパターン
/src/main/com/Sample.scala
継承するパターン
package com import spray.json._ object Sample extends DefaultJsonProtocol { def main(args: Array[String]) { val hoge:List[List[String]] = List( List("hoge", "fuga"), List("piyo", "fuga") ) println(hoge.toJson) } }
traitを使うパターン
package com import spray.json._ object Sample extends App with DefaultJsonProtocol { val hoge:List[List[String]] = List( List("hoge", "fuga"), List("piyo", "fuga") ) println(hoge.toJson) }
どちらも出力は以下の様な感じです。
[["hoge","fuga"],["piyo","fuga"]]
エラーが出るとき
[info] Compiling 1 Scala source to /Users/a-tanaka/Documents/scala_workspace/spray-json/target/scala-2.10/classes... [error] /Users/a-tanaka/Documents/scala_workspace/spray-json/src/main/scala/com/Sample.scala:12: Cannot find JsonWriter or JsonFormat type class for List[List[String]] [error] println(hoge.toJson) [error] ^ [error] one error found [error] (compile:compile) Compilation failed [error] Total time: 0 s, completed 2015/02/11 1:38:59
DefaultJsonProtocolを利用していないために、こんなエラーが出ます。
traitとしてwithでDefaultJsonProtocolを呼ぶか、DefaultJsonProtocolをextendsしてあげるかしてあげましょう。
caseクラスをjson化する
spray/spray-json · GitHub に例としてあがっているものを利用します。
case class Color(name: String, red: Int, green: Int, blue: Int) object MyJsonProtocol extends DefaultJsonProtocol { implicit val colorFormat = jsonFormat4(Color) } import MyJsonProtocol._ val json = Color("CadetBlue", 95, 158, 160).toJson val color = json.convertTo[Color]
case Classを利用している場合は、jsonFormatという関数が用意されているようです。
コンストラクタの引数が4つの場合上記のようにjsonFormat4を利用すれば良いようです。
つまり、case Classのコンストラクタの引数がNの時、jsonFormatNを利用すれば良いらしいです。
caseクラス以外を利用する
implicitオブジェクトを定義する
class Color(val name: String, val red: Int, val green: Int, val blue: Int) object MyJsonProtocol extends DefaultJsonProtocol { implicit object ColorJsonFormat extends RootJsonFormat[Color] { def write(c: Color) = JsArray(JsString(c.name), JsNumber(c.red), JsNumber(c.green), JsNumber(c.blue)) def read(value: JsValue) = value match { case JsArray(Vector(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue))) => new Color(name, red.toInt, green.toInt, blue.toInt) case _ => deserializationError("Color expected") } } } import MyJsonProtocol._ val json = Color("CadetBlue", 95, 158, 160).toJson val color = json.convertTo[Color]
writeという関数でjsonに変換する処理を書いて、
readという関数でjsonから元となるクラスへの変換処理を書けば良いみたいです。
もし、List[List[String]]というクラスをjsonに変換したい場合以下の様なコードを書けばよいかと思います。(read関数は適当です。)
package com import spray.json._ object Sample extends App with DefaultJsonProtocol { implicit object NestedListFormat extends RootJsonFormat[List[List[String]]] { def write (nestedListFormat:List[List[String]]) = JsArray( nestedListFormat.map({ list => JsArray(list.map({ str => JsString(str) }).toVector) }).toVector ) def read (c:JsValue):List[List[String]] = List(List("")) } val hoge:List[List[String]] = List( List("hoge", "fuga"), List("piyo", "fuga") ) println(hoge.toJson) }
toJsonでjson化されるのはかなり楽でいいですね。