1

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

7
  • Your class contains fields which are encapsulated effects. I don't think it should be possible to get an auto derived Codec for this. Commented Dec 6, 2022 at 9:51
  • If you are opened for using other JSON parsers then try jsoniter-scala. It is much handy in derivation and supports parsing and serialization of higher-kinded types out of the box. Also, it is much more efficient in runtime. Commented Dec 6, 2022 at 11:28
  • 1
    Check this updated scastie. Commented Dec 6, 2022 at 12:17
  • Thanks for the help. More or less what I wanted! Commented Dec 6, 2022 at 15:01
  • 1
    Note that Andriy Plokhotnyuk is promoting his own library, so this is not an unbiased recommendation. Commented Dec 6, 2022 at 18:28

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.