From 3e2074612d6c87d91e15eb51d81171a877e03504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Chantepie?= Date: Sun, 24 Dec 2023 00:36:15 +0100 Subject: [PATCH] Fix #836 - Update Scala 3 macro for nesting class support --- .../play/api/libs/json/JsMacroImpl.scala | 3 +-- .../scala/play/api/libs/json/MacroSpec.scala | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/play-json/shared/src/main/scala-3/play/api/libs/json/JsMacroImpl.scala b/play-json/shared/src/main/scala-3/play/api/libs/json/JsMacroImpl.scala index 931f155d0..7e2ed403e 100644 --- a/play-json/shared/src/main/scala-3/play/api/libs/json/JsMacroImpl.scala +++ b/play-json/shared/src/main/scala-3/play/api/libs/json/JsMacroImpl.scala @@ -319,7 +319,6 @@ object JsMacroImpl { // TODO: debug val types = tprElements.map(_._2) val resolve = resolver[Reads, T](forwardExpr, debug)(readsTpe) val compCls = tpr.typeSymbol.companionClass - val compMod = Ref(tpr.typeSymbol.companionModule) val (optional, required) = tprElements.zipWithIndex .map { case ((sym, rpt), i) => @@ -330,7 +329,7 @@ object JsMacroImpl { // TODO: debug val default: Option[Expr[t]] = compCls.declaredMethod(f"$$lessinit$$greater$$default$$" + (i + 1)).headOption.collect { case defaultSym if sym.flags.is(Flags.HasDefault) => - compMod.select(defaultSym).asExprOf[t] + Ref(tpr.typeSymbol.companionModule).select(defaultSym).asExprOf[t] } ReadableField(sym, i, pt, default) diff --git a/play-json/shared/src/test/scala/play/api/libs/json/MacroSpec.scala b/play-json/shared/src/test/scala/play/api/libs/json/MacroSpec.scala index f8cf6c30f..b03edc131 100644 --- a/play-json/shared/src/test/scala/play/api/libs/json/MacroSpec.scala +++ b/play-json/shared/src/test/scala/play/api/libs/json/MacroSpec.scala @@ -505,6 +505,19 @@ class MacroSpec extends AnyWordSpec with Matchers with org.scalatestplus.scalach reader.reads(jsPref2).mustEqual(JsSuccess(pref2)) } + + "handle nesting class" in { + implicit val textIdFormat: Format[TextId] = Json.valueFormat[TextId] + + val nesting = new NestingClass + + val expected = nesting.Test(Some(new TextId("foo"))) + val expectedJson = Json.obj("underlying" -> "foo") + + Json.toJson(expected).mustEqual(expectedJson) + + nesting.Test.format.reads(expectedJson).mustEqual(JsSuccess(expected)) + } } } @@ -602,4 +615,13 @@ object MacroSpec { } case class Preference[V](key: String, kind: PrefKind.Aux[V], value: V) + + class NestingClass { + case class Test(underlying: Option[TextId]) + + object Test { + implicit def format(implicit textIdFormat: Format[TextId]): Format[Test] = + Json.format[Test] + } + } }