I'm facing a strange error where I'm trying to parse a JSON String into a generic case class. My case class looks like this:
final case class LocationAPIObject[F[_]](
countryCode: F[String],
partyId: F[String],
uid: F[String]
)
For a JSON that comes in like this:
val js: JsValue = Json.parse("""{
"countryCode": "us",
"partyId": "123456"
}""")
It results in a parse error:
diverging implicit expansion for type play.api.libs.json.Reads[T]
starting with method Tuple22R in trait GeneratedReads
Here is the sample code that I'm working on: https://scastie.scala-lang.org/aBQIUCTvTECNPgSjCjDFlw
CodePudding user response:
You have diverging implicit expansion
error because you haven't specified type parameter. If you do
val locationAPI = Json.fromJson[LocationAPIObject[Option]](js)
then the error changes to implicit not found: play.api.libs.json.Reads[LocationAPIObject[scala.Option]]. No Json deserializer found for type LocationAPIObject[Option]. Try to implement an implicit Reads or Format for this type.
The case class LocationAPIObject
being parametrized with higher-kinded F
("fields which are encapsulated effects") shouldn't be a problem. The fields are of type F[String]
so in order to derive instances of the type class Reads
or Format
for LocationAPIObject[F]
it should be enough to know instances for F[String]
.
But while this works for example in Circe
import io.circe.Decoder
import io.circe.parser.decode
import io.circe.generic.semiauto
implicit def locDec[F[_]](implicit ev: Decoder[F[String]]): Decoder[LocationAPIObject[F]] =
semiauto.deriveDecoder[LocationAPIObject[F]]
decode[LocationAPIObject[Option]](
"""{
"countryCode": "us",
"partyId": "123456"
}"""
)
// Right(LocationAPIObject(Some(us),Some(123456),None))
for some reason it doesn't in Play json:
implicit def locFormat[F[_]](implicit ev: Format[F[String]]): Format[LocationAPIObject[F]] =
Json.format[LocationAPIObject[F]]
or
implicit def locFormat[F[_]](implicit ev: OFormat[F[String]]): OFormat[LocationAPIObject[F]] =
Json.format[LocationAPIObject[F]]
// No instance of play.api.libs.json.Format is available for F, F, F in the implicit scope (Hint: if declared in the same file, make sure it's declared before)
or
implicit def locReads[F[_]](implicit ev: Reads[F[String]]): Reads[LocationAPIObject[F]] =
Json.reads[LocationAPIObject[F]]
// No instance of play.api.libs.json.Reads is available for F, F, F in the implicit scope (Hint: if declared in the same file, make sure it's declared before)
So the thing seems to be in Play json derivation macros.
The easiest would be to define a codec manually as it was adviced in the comments.