scala周りはまだまだ発展途上なのかすぐに情報が陳腐化してしまい、ググッた情報が「ププッ 今どきそれやらねーよ」というのがしばしば。
Json周りはライブラリがたくさんあってよくワカランチンです。
時期による流行りなのか、人の好みなのか意見が分かれていてなんとも・・・。
まぁ、Play使ってるんだし標準のplay.api.libs.jsonパッケージでいいか、というお話です。
公式のドキュメントはこちら。
http://www.playframework-ja.org/documentation/2.1.5/ScalaJsonCombinators
object Jsonをつかってシリアライズ/デシリアライズ
やりたいのは case class をJSONシリアライズ/デシリアライズ(マーシャリングって言ったほうがいいの?)したいってことで、
- Json#toJson でシリアライズ
- Json#fromJson でデシリアライズ
が基本のようです。
Writes ,Reads を定義
JSONICのようにリフレクションを使ってよろしくやってくれるのかというとそうでもない。(sjsonはリフレクションでやるらしいが細かいこと見てない。)
ということで変換ルールを定義してやらなければならないようだ。
公式ドキュメントによると、
case class Creature(name:String,isDead:Boolean,weight:Float)
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val creatureReads = (
(__ \ "name").read[String] and
(__ \ "isDead").read[Boolean] and
(__ \ "weight").read[Float]
)(Creature)
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val creatureWrites = (
(__ \ "name").write[String] and
(__ \ "isDead").write[Boolean] and
(__ \ "weight").write[Float]
)(unlift(Creature.unapply))
こんな感じでimplicitなreads,writesをスコープ内に宣言せよと。
…なんかめんどくせーよ
こ、これっていいの?? 何かDAOをめんどくせーなーと思いながら実装したあの日々が…。
と思ったらですね、
def reads[A]: Reads[A]
def writes[A]: Writes[A]
こんなのがあるんですよ。単純なReads,Writesなら生成してくれるようでホッとしました。
scala> implicit val creatureWrites = Json.writes[Creature]
creatureWrites: play.api.libs.json.OWrites[Creature] = play.api.libs.json.OWrites$$anon$2@55093b47
scala> Json.toJson(Creature("Cow",true,456))
res73: play.api.libs.json.JsValue = {"name":"Cow","isDead":true,"weight":456.0}
scala> implicit val creatureReads=Json.reads[Creature]
creatureReads: play.api.libs.json.Reads[Creature] = play.api.libs.json.Reads$$anon$8@4fcee80f
scala> val strJson = """
| {"name":"Zombi","isDead":false,"weight":30.5}
| """
strJson: String =
"
{"name":"Zombi","isDead":false,"weight":30.5}
"
scala> Json.fromJson(Json.parse(strJson))
res82: play.api.libs.json.JsResult[Creature] = JsSuccess(Creature(Zombi,false,30.5),)
JsResult
fromJsonを使った場合、JsResultというOption型みたいなやつがかえされる。
なんでもパースに失敗した時にJsError型を返すことで失敗した原因をうまいこと返す仕組みらしい。