The following shows how to use the alternative typeclass in JsResult
The following imports are assumed in all examples:
import play.api.libs.json._
import play.api.libs.functional.syntax._
Lets say we have the following case class
case class Value(name: String, percentage: Float)
object Value {
implicit val valueFormat = Json.format[Value]
}
Lets say that the Value class used to have a field called "title" instead of "name" and we want to be backwards compatible. We would like a way to parse incoming JSON with "title" instead of "name" to be correct.
When you call Json.format[Value]
you are automatically building both a Reads[Value]
and a Writes[Value]
out of the case class.
However, if you want a field to have a different name in the Json than in the class, you will have to manually build
Reads
and/or Writes
(Format
is simply the combination of these two).
Let us create a manual Reads[Value]
:
case class Value(name: String, percentage: Float)
object Value {
implicit val valueReads =
((__ \ "name").read[String] and (__ \ "percentage").read[Float])(Value.apply _)
Notice the and
function? What that is doing is applying the result of the first calculation (the "name" calculation) to the next calculation (the "percentage" calculation). and
states that if either one of them fails, the whole thing fails (but it will keep the results of both).
There is a function or
(aliased |
) that will instead of failing both, it will pick (alternate) between the two the one that successed. If both successed, then it picks the first one (so order matters. Put the "new" field name first).
Let us create a Reads[Value]
that will accept "name" or
"title".
case class Value(name: String, percentage: Float)
object Value {
implicit val valueReads =
((__ \ "name").read[String] or (__ \ "title").read[String] and (__ \ "percentage").read[Float])(Value.apply _)
Notice the or
between tne "name" and "title" calculations. We still want an and
for the "percentage".
Now, when you call JsValue.validate[Value]
, it will try to validate "name". But if it fails, it will look for "title". If that fails, then a JsError
is return telling you that it couldn't find neither name or title.