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.