ドキュメントよりも、もとのヤツのほうが参考になる? http://mandubian.com/2012/10/29/unveiling-play-2-dot-1-json-api-part3-json-transformers/
あと元ソースのコメント play.api.libs.json.JsPath.scala
import play.api.libs.json._
import play.api.libs.json.Reads._ //of[Type]を使うのなら忘れない
val json = Json.obj(
"key1" -> "value1",
"key2" -> Json.obj(
"key21" -> 123,
"key22" -> true,
"key23" -> Json.arr("alpha", "beta", "gamma"),
"key24" -> Json.obj(
"key241" -> 234.123,
"key242" -> "value242"
)
),
"key3" -> 234
)
val jsonTransformer = (__ \ 'key2).json.pickBranch(
of[JsObject].map{ case obj:JsObject =>
JsObject( Seq(("key21", obj \ "key21") , ("key24", obj \ "key24")))
}
)
scala> json.validate(jsonTransformer)
res: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsSuccess({"key2":{"key21":123,"key24":{"key241":234.123,"key242":"value242"}}},/key2)
scala> Json.prettyPrint(json.validate(jsonTransformer).get)
res2: String =
{
"key2" : {
"key21" : 123,
"key24" : {
"key241" : 234.123,
"key242" : "value242"
}
}
}
import play.api.libs.json._
import play.api.libs.json.Reads._ //of[Type]を使うのなら忘れない
val json = Json.obj(
"key1" -> "value1",
"key2" -> Json.obj(
"key21" -> 123,
"key22" -> true,
"key23" -> Json.arr("alpha", "beta", "gamma"),
"key24" -> Json.obj(
"key241" -> 234.123,
"key242" -> "value242"
)
),
"key3" -> 234
)
// key2をただのbooleanにする
val transformer1 = __.json.update( (__ \ 'key2).json.put(JsBoolean(true)))
val transformer2 = (__ \ 'key2).json.update( of[JsObject].map(x => JsBoolean(true)))
scala> json.validate(transformer1)
res4: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsSuccess({"key1":"value1","key2":true,"key3":234},)
scala> json.validate(transformer2)
res6: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsSuccess({"key1":"value1","key2":true,"key3":234},/key2)
{
"name" : "hoge",
"sex" : "female",
"id" : 123456
}
{
"name" : "fuga",
"sex" : "male",
"id" : "123457"
}
- sexってのはどうやらEnum的な(ここではmale/female以外の文字列は飛んでこないとします)
- id は文字列だったり数値だったり…(ここでは数値は文字列に直せばOkとします)
case class User(name: String, sex: Sex, id: String)
object Sex {
case object Male extends Sex("male")
case object Female extends Sex("female")
def apply(sex: String) = sex match {
case Male.sex => Male
case Female.sex => Female
}
}
sealed abstract class Sex(val sex: String)
import play.api.libs.json._
import play.api.libs.functional.syntax._
import play.api.data.validation.ValidationError
implicit val sexReader = new Reads[Sex] {
def reads(json: JsValue): JsResult[Sex] = json match {
case JsString(x) => Try(JsSuccess(Sex(x))).getOrElse(JsError())
case _ => JsError()
}
}
implicit val userReader = (
(__ \ 'name).read[String] ~
(__ \ 'sex).read[Sex] ~
(__ \ 'id).read[JsValue].collect(ValidationError("validate.error")) {
case JsString(x) => x
case JsNumber(x) => x.toString}
)(User)
もうちょっとあっさりしてみる
import play.api.libs.json.Reads._
implicit val userReader = (
(__ \ 'name).read[String] ~
(__ \ 'sex).read[Sex] ~
(__ \ 'id).read(of[String] or of[Int].map(_.toString))
)(User)