Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for play 2.9 / scala 3 generators #696

Merged
merged 18 commits into from
Jun 26, 2024
Merged

Add support for play 2.9 / scala 3 generators #696

merged 18 commits into from
Jun 26, 2024

Conversation

mbryzek
Copy link
Collaborator

@mbryzek mbryzek commented Jun 25, 2024

Play 2.9 supports Scala3. This change provides a new generator to support scala3.

If you would like to use the Scala3 code generator, use the play_2_9_scala_3_client of play_2_x_scala_3_json generators. Example diff of apibuilder/config:

-        - generator: play_2_8_client
+        - generator: play_2_9_scala_3_client

The main change in the generator is to refactor the play json readers/writers for union types. The main difference in scala3 is how the types are resolved which is a bit stricter in resolving parent types and in finding potential duplicate implicits.

Our approach here is to remove implicit readers/writers for models that are part of a union type and to refactor the union type readers/writers so that they can apply universally to models.

We also have a gap with identifying union readers for collections - in this PR we add support to explicitly serialize/deserialize Seq[T] where T is a union type - but over time would like to explore more complete solutions.

There is one change in readers that we applied to both scala2 and scala3. Rather than relying on implicits when deserializing an instance of a union type to a JS Object, we now explicitly invoke the correct underlying method after we match on discriminator. Example:

Old:

    implicit def jsonReadsBillingTransactionMetadata: play.api.libs.json.Reads[TransactionMetadata] = (js: play.api.libs.json.JsValue) => {
      def readDiscriminator(discriminator: String) = {
        discriminator match {
          case "shipping_label" => js.validate[io.flow.billing.v0.models.TransactionMetadataShippingLabel]
          case "channel" => js.validate[io.flow.billing.v0.models.TransactionMetadataChannel]
          ...
          case other => play.api.libs.json.JsSuccess(io.flow.billing.v0.models.TransactionMetadataUndefinedType(other))
        }
      }
      (js \ "discriminator").validate[String] match {
        case e: play.api.libs.json.JsError => e
        case s: play.api.libs.json.JsSuccess[String] => readDiscriminator(s.value)
      }
    }

New:

    implicit def jsonReadsBillingTransactionMetadata: play.api.libs.json.Reads[TransactionMetadata] = (js: play.api.libs.json.JsValue) => {
      def readDiscriminator(discriminator: String) = {
        discriminator match {
          case "shipping_label" => jsonReadsBillingTransactionMetadataShippingLabel.reads(js)
          case "channel" => jsonReadsBillingTransactionMetadataChannel.reads(js)
          ...
          case other => play.api.libs.json.JsSuccess(io.flow.billing.v0.models.TransactionMetadataUndefinedType(other))
        }
      }
      (js \ "discriminator").validate[String] match {
        case e: play.api.libs.json.JsError => e
        case s: play.api.libs.json.JsSuccess[String] => readDiscriminator(s.value)
      }
    }

This change is expected and tested to be fully backwards compatible.

@mbryzek mbryzek merged commit 2829516 into main Jun 26, 2024
2 checks passed
@mbryzek mbryzek deleted the scala3_play branch June 26, 2024 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant