Home:ALL Converter>Generated play json implicit instances cause StackOverflowError

Generated play json implicit instances cause StackOverflowError

Ask Time:2019-11-07T18:47:50         Author:jbracker

Json Formatter

I have the following code:

import play.api.libs.json._
object Test {
   sealed trait T
   case class A(s: String) extends T

   implicit val writesA: OWrites[A] = Json.writes[A]
   implicit val writesT: OWrites[T] = Json.writes[T]

   def main(args: Array[String]): Unit = {
      val x = A("str")
      println(Json.toJson[T](x)(writesT))
   }
}

It causes a StackOverflowError when run.

If I add lazy in front of writesT, the StackOverflowError goes away and everything works:

import play.api.libs.json._
object Test {
   sealed trait T
   case class A(s: String) extends T

   implicit val writesA: OWrites[A] = Json.writes[A]
   implicit lazy val writesT: OWrites[T] = Json.writes[T]

   def main(args: Array[String]): Unit = {
      val x = A("str")
      println(Json.toJson[T](x)(writesT))
   }
}

The StackOverflowError also disappears when I move the implicits into the main function:

import play.api.libs.json._
object Test {
   sealed trait T
   case class A(s: String) extends T

   def main(args: Array[String]): Unit = {
      implicit val writesA: OWrites[A] = Json.writes[A]
      implicit val writesT: OWrites[T] = Json.writes[T]
      val x = A("str")
      println(Json.toJson[T](x)(writesT))
   }
}

Can anyone explain to me why I get a StackOverflowError in the first case?

My suspicion is that it has something to do with initialization orders and the macros that play-json uses in the background. But if that is the case I don't get why using lazy helps, because the code should still be generated at compile time and simply evaluating it later at runtime shouldn't change anything. Apparently in the later cases the writesA instance is found by writesT but not in the first case. Why does adding lazy resolve a compile-time issue with the resolution of implicits and macro code generation?

Or is this an issue on a completely different level?

I am using Scala 2.12.3 and play-json 2.6.2.

Author:jbracker,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/58747105/generated-play-json-implicit-instances-cause-stackoverflowerror
yy