playframework / play-json

The Play JSON library
Apache License 2.0
361 stars 133 forks source link

[Feature] Support typeclass derivation (`derives`) from Scala 3 #1089

Open gaeljw opened 3 weeks ago

gaeljw commented 3 weeks ago

This is a feature request, not an issue.

Following the discussion on this Reddit thread, it would be nice if it was supported OOB by play-json. I'm copying the relevant part of the thread here.

From @SnooDogs8860:

In Scala 2.13, and play-json, I used the following pattern to serialize/de-serialize between case classes and Json:

import play.api.libs.json.{Format, Json}

object WelcomeResult {
  implicit val format = Json.format[WelcomeResult]
}

case class WelcomeResult(service: String)

defining implicit formatin the companion object of the case class, made it easily visible from outside, so the following code worked without > even requiring an extra import:

val welcome = WelcomeResult("test")
val json = Json.toJson(welcome)

In Scala 3 I saw the type class derivation feature and though I could take advantage of it by a. making the code more compact. b. defining such a default formatting only once in a generic way in the type class.

This is the implementation I have in mind:

case class WelcomeResult(service: String) derives Format 

From @mkatrenik and @SnooDogs8860, the implementation could like the following (using another custom trait as modifying the PlayJSON one was not possible):

trait JsonFormat[T] extends Format[T]

object JsonFormat:

  inline def derived[T]: JsonFormat[T] =
    new JsonFormat[T]:
      override def reads(json: JsValue): JsResult[T] = Json.reads[T].reads(json)

      override def writes(o: T): JsValue = Json.writes[T].writes(o)

It might only be a matter of opening a PR with the code above, I don't know how much changes would be required in play-json code to integrate it. I guess most of the "issue" is to have it only for Scala 3 and avoiding duplication of having a source file for Scala 2 and one for Scala3?