Search code examples
jsonscalarecursionplayframeworkplay-json

Json implicit format with recursive class definition


I have a recursive class defined :

case class SettingsRepository(id: Option[BSONObjectID],
                          name: Option[String],
                          children: Option[List[SettingsRepository]])

with a JSON implicit format as below :

implicit val repositoryFormat = Json.format[SettingsRepository]

How can I do to resolve this compilation error? :

No implicit format for Option[List[models.practice.SettingsRepository]] available.
In /path/to/the/file.scala:95

95 implicit val repositoryFormat = Json.format[SettingsRepository] 

I tried to define a lazy reads/write/format wrapper without any success... Anyone know a clean way to do that?


Solution

  • As you've discovered, you can't use the JSON inception macro here, but you can write your own Format (note that I've replaced BSONObjectID with Long for the sake of a complete working example):

    import play.api.libs.functional.syntax._
    import play.api.libs.json._
    
    case class SettingsRepository(
      id: Option[Long],
      name: Option[String],
      children: Option[List[SettingsRepository]]
    )
    
    implicit val repositoryFormat: Format[SettingsRepository] = (
      (__ \ 'id).formatNullable[Long] and
      (__ \ 'name).formatNullable[String] and
      (__ \ 'children).lazyFormatNullable(implicitly[Format[List[SettingsRepository]]])
    )(SettingsRepository.apply, unlift(SettingsRepository.unapply))
    

    The trick is providing an explicit type annotation and using implicitly rather than just a type parameter on lazyFormatNullable.