resolvers += Resolver.bintrayRepo("larousso", "maven")
libraryDependencies += "com.adelegue" %% "playjson-extended" % "X.X.X"
With play json you can write this :
import play.api.libs.json._
case class Village(name: String)
object Village {
implicit val reads = Json.reads[Village]
}
case class Viking(name: String, surname: String, weight: Int, village: Seq[Village])
implicit val reads = Json.reads[Viking]And if you want to add advanced validation you have to write this
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
case class Village(name: String)
object Village {
implicit val reads = Json.reads[Village]
}
case class Viking(name: String, surname: String, weight: Int, village: Seq[Village])
implicit val reads = (
(__ \ 'name).read[String] and
(__ \ 'surname).read[String] and
(__ \ 'weight).read[Int](min(0) keepAnd max(150)) and
(__ \ 'village).read[Seq[Village]]
)(Viking.apply _)Here we have to write all the parsing rules just to validate weight.
With this lib you can just write
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import shapeless._
import syntax.singleton._
import playjson.rules._
case class Village(name: String)
object Village {
implicit val reads = Json.reads[Village]
}
case class Viking(name: String, surname: String, weight: Int, village: Seq[Village])
implicit val reads: Reads[Viking] = jsonRead[Viking].withRules(
'weight ->> read(min(0) keepAnd max(150))
)You can just generate a Reads[T] using shapeless instead of scala macro
import play.api.libs.json._
import playjson.reads._
val monMojoReads: Reads[Viking] = hReads[Viking]Transform json before converting to case class :
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import shapeless._
import syntax.singleton._
import playjson.rules._
import playjson.transformation._
case class Village(name: String)
object Village {
implicit val reads = Json.reads[Village]
}
case class Viking(name: String, surname: String, weight: Int, village: Seq[Village])
val reads: Reads[Viking] =
transform(
((__ \ 'theName) to (__ \ 'name)) and
((__ \ 'theSurname) to (__ \ 'surname)) and
((__ \ 'theVillage) to (__ \ 'village))
) andThen Json.reads[Viking]
val jsResult: JsResult[Viking] = reads.reads(Json.obj(
"theName" -> "Ragnar",
"theSurname" -> "Lothbrok",
"theVillage" -> Seq(Json.obj("name" -> "Kattegat")),
"weight" -> 2
))You can combine both rules and transformations
val reads: Reads[Viking] =
transform(
((__ \ 'theName) to (__ \ 'name)) and
((__ \ 'theSurname) to (__ \ 'surname)) and
((__ \ 'theVillage) to (__ \ 'village))
) andThen jsonRead[Viking].withRules(
'weight ->> read(min(0) keepAnd max(150)) and
'name ->> read(pattern(".*".r)) and
'surname ->> read(pattern(".*".r))
)Or use reads generated from shapeless LabelledGeneric :
val reads: Reads[Viking] =
transform(
((__ \ 'theName) to (__ \ 'name)) and
((__ \ 'theSurname) to (__ \ 'surname)) and
((__ \ 'theVillage) to (__ \ 'village))
) andThen hReads[Viking]sbt "release with-defaults"