https://github.com/xuwei-k/play-json-extra
昨日の夜、数時間くらいで適当に作った。*1モチベーションとしては
case class Foo(a: Int, b: String, c: List[String])
というようなcase classがあった場合、以下のようにReads*2を書くわけですが
implicit val fooReads: Reads[Foo] = ( (__ \ "a").read[Int] and (__ \ "b").read[String] and (__ \ "c").read[List[String]] )(Foo.apply _)
上記のようにそのままFoo.applyに渡す場合、Int, String, List[String] の3つの型を書かないといけないのって面倒だと思いませんか?Fooの型から推論できそうですよね?というか、推論できるJsonライブラリがScalaで存在する( https://github.com/argonaut-io/argonaut/ )ので、playでももちろん出来るはずです。というわけで作りました。
使い方は
import play.jsonext._ import play.api.libs.json._ implicit val fooReads: Reads[Foo] = CaseClassReads(Foo.apply _)( "a", "b", "c" )
という感じです。型は書かずにkeyだけ書けばよいです。マクロは使ってません。
play2のJsonには、case classのフィールド名と、Jsonのkey名が同じで良い場合、それさえ省略して
implicit val fooReads: Reads[Foo] = Json.reads[Foo]
で全部やってくれるものもあります。(マクロ使って、case classのフィールド名をコンパイル時に取得してる)
http://www.playframework.com/documentation/2.2.2/ScalaJsonInception
https://github.com/playframework/playframework/blob/2.2.2/framework/src/play-json/src/main/scala/play/api/libs/json/Json.scala#L151-L169
しかし、Playのマクロの使う場合の欠点として
- applyやunapplyがオーバーロードされてるなど、特定の条件でうまくいかない場合がある(?) *3
- うかつにcase classのフィールド名を変えてしまうと、jsonのkeyも変わってしまって、シリアライズやデシリアライズの挙動も変わってしまう
- case classのフィールド名と、jsonのkey名を別のものにしたい場合、最初に書いたように
(__ \ "a").read[Int] and
と型まで書かないといけなくなる - なんとなくマクロは使いたくない人(いるのか?)
というのがあります。
逆に言うと、それだけ(andの形式で書くときより、型が省略できるだけ)で、それ以外にすごいことしてくれるわけではありませんが、地味に便利だと思います。
sonatype経由で、maven centralにpublishしてあるので、githubのREADMEの通りにlibraryDependenciesを1行加えれば使えるはずです。
上記では、Readsの例で説明しましたが、ほぼ同じような感じで、WritesとFormatsの場合も定義してあります。
あと、(このあたりのベストプラクティスがよくわかってないのですが)play-jsonの依存のスコープはcompileではなくprovidedになっていて、明示的に加えないといけないので注意してください。