Skip to content

Conversation

@plaflamme
Copy link

@plaflamme plaflamme commented Feb 7, 2026

Address #19891 for sttp4 clients.

@Fish86

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • File the PR against the correct branch: master (upcoming 7.x.0 minor release - breaking changes with fallbacks), 8.0.x (breaking changes without fallbacks)
  • If your PR solves a reported issue, reference it using GitHub's linking syntax (e.g., having "fixes #123" present in the PR description)
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Adds oneOf support to the Scala sttp4 client with sealed-trait parents and inline members, and aligns JSON and request/response handling with sttp4. Fixes discriminator mapping and makes circe constructor-name mapping total; adds a circe sample and updates to sttp 4.0.15 (fixes #19891).

  • New Features

    • oneOf: sealed-trait parents; inline case classes when used by a single parent; supports discriminator + mapping; removes discriminator fields in children; circe/json4s codecs; tests incl. empty members; circe transformConstructorNames is total to avoid match errors.
    • JSON & API alignment: .body(asJson(...)); Either[ResponseException[String], T]; pass Option[String] directly to .header; container query/form values encode via mkString(","); default Seq params = Seq.empty; AnyType/object map to circe Json/JsonObject or json4s JValue/JObject based on jsonLibrary.
    • Enums & samples/deps: enums replaced with sealed-trait ADTs with per-type codecs; new scala-sttp4-circe sample and config; sttp client 4.0.15; add circe-generic and circe-generic-extras.
  • Migration

    • Enums are now sealed traits; update pattern matches/usages and imports.
    • oneOf parents are sealed traits; some members are generated inline in the parent file; adjust imports if referenced directly.
    • Response type is Either[ResponseException[String], T] (was ResponseException[String, Exception]).
    • Container query/form values now encode via mkString(","); verify server expectations if relying on previous formatting.

Written for commit 7aba995. Summary will update on new commits.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 8 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="modules/openapi-generator/src/main/resources/scala-sttp4/api.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/scala-sttp4/api.mustache:38">
P2: Request bodies are now always JSON‑serialized with `asJson(...)`, which breaks operations that consume non‑JSON media types by sending JSON instead of the raw body.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache:52">
P2: json4s oneOf deserialization aborts on first mismatch because `Extraction.extract` throws, so later oneOf types are never tried.</violation>

<violation number="2" location="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache:74">
P2: Discriminator handling hardcodes the Scala class name as the wire value, ignoring OpenAPI discriminator mappings, so specs with mapped discriminator values will fail to deserialize/serialize correctly.</violation>

<violation number="3" location="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache:172">
P2: Inline oneOf member case classes are generated inside the parent model file, but the parent model’s import list isn’t augmented with the child models’ imports. If a oneOf member uses a type not referenced by the parent, the inline case class will compile without the necessary import.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

{{/vendorExtensions.x-isEnum}}
{{#vendorExtensions.x-isRegularModel}}
{{^isEnum}}
case class {{classname}}(
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Inline oneOf member case classes are generated inside the parent model file, but the parent model’s import list isn’t augmented with the child models’ imports. If a oneOf member uses a type not referenced by the parent, the inline case class will compile without the necessary import.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache, line 172:

<comment>Inline oneOf member case classes are generated inside the parent model file, but the parent model’s import list isn’t augmented with the child models’ imports. If a oneOf member uses a type not referenced by the parent, the inline case class will compile without the necessary import.</comment>

<file context>
@@ -15,46 +20,218 @@ import {{import}}
+{{/vendorExtensions.x-isEnum}}
+{{#vendorExtensions.x-isRegularModel}}
+{{^isEnum}}
+case class {{classname}}(
+  {{#vars}}
+  {{#description}}
</file context>
Fix with Cubic

@wing328
Copy link
Member

wing328 commented Feb 7, 2026

thanks for the PR

cc @clasnake (2017/07), @shijinkui (2018/01), @ramzimaalej (2018/03), @chameleon82 (2020/03), @Bouillie (2020/04) @Fish86 (2023/06)

@wing328
Copy link
Member

wing328 commented Feb 7, 2026

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache:107">
P2: `transformConstructorNames` is defined as a partial match over only `x-oneOfMembers`. Because `x-oneOfMembers` excludes shared oneOf subtypes, the function is not total and will throw `MatchError` when encoding/decoding those subtypes. Add a default case (identity) so unmapped constructor names don’t crash serialization.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@plaflamme
Copy link
Author

@wing328 I've updated the samples in e594023

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/scala-sttp4/model.mustache:110">
P2: Wildcard `case other` is emitted inside the oneOfMembers loop, so the first wildcard matches everything and makes subsequent member cases unreachable; only the first oneOf member can be encoded/decoded.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][Scala] OneOf generates incorrect classes.

2 participants