2
votes

I have problems to find how to convert a json doc with a single value to a case class. Here is the json:

{
  "ax" : {
           "bx" : "value1",
           "by" : "value2
         }
}

Here are the case classes:

case class B(bx: String, by: String)
case class A(ax: B)

And here are the reads:

import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._

object Implicits {
     implicit val bReads: Reads[B] = (
        ( __ \ "bx" ).read[String] ~
        ( __ \ "by" ).read[String]
     ) ( B.apply _ )    

     implicit val aReads: Reads[A] = (
        ( __ \ "ax" ).read[B]
     ) ( A.apply _ )
}

The second implicit doesn't compile with the following error:

Error:(X, Y) overloaded method value read with alternatives:
(t: B)play.api.libs.json.Reads[B] <and>
(implicit r: play.api.libs.json.Reads[B])play.api.libs.json.Reads[B]
cannot be applied to ((B, Option[String]) => A)
   ( __ \ "ax" ).read[B] 

In order to make it work, I need to change the A class to have another value:

case class A(ax: B, temp: Option[String])

And the implicit read:

implicit val aReads: Reads[A] = (
   ( __ \ "ax" ).read[B] ~
   ( __ \ "temp" ).readNullable[String]
) ( A.apply _ )

How the reads can be done without having to add something that doesn't exists to the classes? Any ideas?

1
Side note: The Reads for A and B ought to go in their companion objects, and the implicits will be resolved correctly. Then, there is no need to import the implicits.. unless you need to switch them out for some reason. In which case, explicit calls would be more clear, anyway.Michael Zajac
Thanks you. I will keep that in mind.Darien

1 Answers

14
votes

The Reads instance for a single param case class is a bit awkward with Play JSON, but the following should work

 implicit val reads: Reads[A] =
    (JsPath \ "ax").read[B].map(A.apply)