From 6fb8aba1cc891098343f4e1509dc1da99a0552d4 Mon Sep 17 00:00:00 2001 From: Michael Bryzek Date: Wed, 31 Jul 2024 07:18:31 -0400 Subject: [PATCH] Add workaround for invalid UndefinedType serialization (#704) --- .../resources/example-union-types-ning-client.txt | 12 +++++++++++- .../test/resources/example-union-types-play-23.txt | 12 +++++++++++- lib/src/test/resources/scala-union-enums-json.txt | 12 +++++++++++- .../scala-union-models-json-union-type-writers.txt | 12 +++++++++++- lib/src/test/resources/scala-union-models-json.txt | 12 +++++++++++- .../src/main/scala/models/Play2Json.scala | 13 ++++++++++++- 6 files changed, 67 insertions(+), 6 deletions(-) diff --git a/lib/src/test/resources/example-union-types-ning-client.txt b/lib/src/test/resources/example-union-types-ning-client.txt index 42c55931..6201b6d0 100644 --- a/lib/src/test/resources/example-union-types-ning-client.txt +++ b/lib/src/test/resources/example-union-types-ning-client.txt @@ -319,7 +319,17 @@ package io.apibuilder.example.union.types.v0.models { obj match { case x: io.apibuilder.example.union.types.v0.models.Foo => play.api.libs.json.Json.obj("foo" -> play.api.libs.json.JsString(x.toString)) case x: io.apibuilder.example.union.types.v0.models.Bar => play.api.libs.json.Json.obj("bar" -> play.api.libs.json.JsString(x.toString)) - case x: io.apibuilder.example.union.types.v0.models.FoobarUndefinedType => sys.error(s"The type[io.apibuilder.example.union.types.v0.models.FoobarUndefinedType] should never be serialized") + case x: io.apibuilder.example.union.types.v0.models.FoobarUndefinedType => { + scala.util.Try { + // If we received a JSON object - echo it back. This is a workaround for a bug in + // serialization for unions w/out discriminators where they sometimes have the + // type wrapper and sometimes do not + play.api.libs.json.Json.parse(x.description).asInstanceOf[play.api.libs.json.JsObject] + } match { + case scala.util.Success(o) => o + case scala.util.Failure(_) => sys.error("The type[io.apibuilder.example.union.types.v0.models.FoobarUndefinedType] should never be serialized") + } + } } } implicit def jsonWritesApidocExampleUnionTypesFoobar: play.api.libs.json.Writes[Foobar] = { diff --git a/lib/src/test/resources/example-union-types-play-23.txt b/lib/src/test/resources/example-union-types-play-23.txt index 8bb8a073..ef991232 100644 --- a/lib/src/test/resources/example-union-types-play-23.txt +++ b/lib/src/test/resources/example-union-types-play-23.txt @@ -319,7 +319,17 @@ package io.apibuilder.example.union.types.v0.models { obj match { case x: io.apibuilder.example.union.types.v0.models.Foo => play.api.libs.json.Json.obj("foo" -> play.api.libs.json.JsString(x.toString)) case x: io.apibuilder.example.union.types.v0.models.Bar => play.api.libs.json.Json.obj("bar" -> play.api.libs.json.JsString(x.toString)) - case x: io.apibuilder.example.union.types.v0.models.FoobarUndefinedType => sys.error(s"The type[io.apibuilder.example.union.types.v0.models.FoobarUndefinedType] should never be serialized") + case x: io.apibuilder.example.union.types.v0.models.FoobarUndefinedType => { + scala.util.Try { + // If we received a JSON object - echo it back. This is a workaround for a bug in + // serialization for unions w/out discriminators where they sometimes have the + // type wrapper and sometimes do not + play.api.libs.json.Json.parse(x.description).asInstanceOf[play.api.libs.json.JsObject] + } match { + case scala.util.Success(o) => o + case scala.util.Failure(_) => sys.error("The type[io.apibuilder.example.union.types.v0.models.FoobarUndefinedType] should never be serialized") + } + } } } implicit def jsonWritesApidocExampleUnionTypesFoobar: play.api.libs.json.Writes[Foobar] = { diff --git a/lib/src/test/resources/scala-union-enums-json.txt b/lib/src/test/resources/scala-union-enums-json.txt index eebf608c..9e32a12f 100644 --- a/lib/src/test/resources/scala-union-enums-json.txt +++ b/lib/src/test/resources/scala-union-enums-json.txt @@ -12,7 +12,17 @@ def jsObjectUserType(obj: test.apidoc.apidoctest.v0.models.UserType): play.api.l obj match { case x: test.apidoc.apidoctest.v0.models.MemberType => play.api.libs.json.Json.obj("member_type" -> play.api.libs.json.JsString(x.toString)) case x: test.apidoc.apidoctest.v0.models.RoleType => play.api.libs.json.Json.obj("role_type" -> play.api.libs.json.JsString(x.toString)) - case x: test.apidoc.apidoctest.v0.models.UserTypeUndefinedType => sys.error(s"The type[test.apidoc.apidoctest.v0.models.UserTypeUndefinedType] should never be serialized") + case x: test.apidoc.apidoctest.v0.models.UserTypeUndefinedType => { + scala.util.Try { + // If we received a JSON object - echo it back. This is a workaround for a bug in + // serialization for unions w/out discriminators where they sometimes have the + // type wrapper and sometimes do not + play.api.libs.json.Json.parse(x.description).asInstanceOf[play.api.libs.json.JsObject] + } match { + case scala.util.Success(o) => o + case scala.util.Failure(_) => sys.error("The type[test.apidoc.apidoctest.v0.models.UserTypeUndefinedType] should never be serialized") + } + } } } implicit def jsonWritesAPIBuilderTestUserType: play.api.libs.json.Writes[UserType] = { diff --git a/lib/src/test/resources/scala-union-models-json-union-type-writers.txt b/lib/src/test/resources/scala-union-models-json-union-type-writers.txt index 2512340b..a3a7fe99 100644 --- a/lib/src/test/resources/scala-union-models-json-union-type-writers.txt +++ b/lib/src/test/resources/scala-union-models-json-union-type-writers.txt @@ -2,7 +2,17 @@ def jsObjectUser(obj: test.apidoc.apidoctest.v0.models.User): play.api.libs.json obj match { case x: test.apidoc.apidoctest.v0.models.RegisteredUser => play.api.libs.json.Json.obj("registered_user" -> test.apidoc.apidoctest.v0.models.json.jsObjectRegisteredUser(x)) case x: test.apidoc.apidoctest.v0.models.GuestUser => play.api.libs.json.Json.obj("guest_user" -> test.apidoc.apidoctest.v0.models.json.jsObjectGuestUser(x)) - case x: test.apidoc.apidoctest.v0.models.UserUndefinedType => sys.error(s"The type[test.apidoc.apidoctest.v0.models.UserUndefinedType] should never be serialized") + case x: test.apidoc.apidoctest.v0.models.UserUndefinedType => { + scala.util.Try { + // If we received a JSON object - echo it back. This is a workaround for a bug in + // serialization for unions w/out discriminators where they sometimes have the + // type wrapper and sometimes do not + play.api.libs.json.Json.parse(x.description).asInstanceOf[play.api.libs.json.JsObject] + } match { + case scala.util.Success(o) => o + case scala.util.Failure(_) => sys.error("The type[test.apidoc.apidoctest.v0.models.UserUndefinedType] should never be serialized") + } + } } } implicit def jsonWritesAPIBuilderTestUser: play.api.libs.json.Writes[User] = { diff --git a/lib/src/test/resources/scala-union-models-json.txt b/lib/src/test/resources/scala-union-models-json.txt index 953887e1..88ccad3c 100644 --- a/lib/src/test/resources/scala-union-models-json.txt +++ b/lib/src/test/resources/scala-union-models-json.txt @@ -64,7 +64,17 @@ def jsObjectUser(obj: test.apidoc.apidoctest.v0.models.User): play.api.libs.json obj match { case x: test.apidoc.apidoctest.v0.models.RegisteredUser => play.api.libs.json.Json.obj("registered_user" -> test.apidoc.apidoctest.v0.models.json.jsObjectRegisteredUser(x)) case x: test.apidoc.apidoctest.v0.models.GuestUser => play.api.libs.json.Json.obj("guest_user" -> test.apidoc.apidoctest.v0.models.json.jsObjectGuestUser(x)) - case x: test.apidoc.apidoctest.v0.models.UserUndefinedType => sys.error(s"The type[test.apidoc.apidoctest.v0.models.UserUndefinedType] should never be serialized") + case x: test.apidoc.apidoctest.v0.models.UserUndefinedType => { + scala.util.Try { + // If we received a JSON object - echo it back. This is a workaround for a bug in + // serialization for unions w/out discriminators where they sometimes have the + // type wrapper and sometimes do not + play.api.libs.json.Json.parse(x.description).asInstanceOf[play.api.libs.json.JsObject] + } match { + case scala.util.Success(o) => o + case scala.util.Failure(_) => sys.error("The type[test.apidoc.apidoctest.v0.models.UserUndefinedType] should never be serialized") + } + } } } implicit def jsonWritesAPIBuilderTestUser: play.api.libs.json.Writes[User] = { diff --git a/scala-generator/src/main/scala/models/Play2Json.scala b/scala-generator/src/main/scala/models/Play2Json.scala index e9e4a2e1..cba089d3 100644 --- a/scala-generator/src/main/scala/models/Play2Json.scala +++ b/scala-generator/src/main/scala/models/Play2Json.scala @@ -332,7 +332,18 @@ case class Play2Json( val json = getJsonValueForUnion(t.unionType.datatype, "x") s"""case x: ${t.typeName} => play.api.libs.json.Json.obj("${t.unionType.discriminatorName}" -> $json)""" }.mkString("\n").indentString(4), - s""" case x: ${union.undefinedType.datatype.fullName} => sys.error(s"The type[${union.undefinedType.datatype.fullName}] should never be serialized")""", + s"""case x: ${union.undefinedType.datatype.fullName} => { + | scala.util.Try { + | // If we received a JSON object - echo it back. This is a workaround for a bug in + | // serialization for unions w/out discriminators where they sometimes have the + | // type wrapper and sometimes do not + | play.api.libs.json.Json.parse(x.description).asInstanceOf[play.api.libs.json.JsObject] + | } match { + | case scala.util.Success(o) => o + | case scala.util.Failure(_) => sys.error("The type[${union.undefinedType.datatype.fullName}] should never be serialized") + | } + |} + |""".stripMargin.indent(4).stripTrailing(), " }", "}" ).mkString("\n")