Skip to content

[Swift6][Client] Make Swift 6 generator thread safe#23191

Open
4brunu wants to merge 7 commits intoOpenAPITools:masterfrom
4brunu:feature/swift6-thread-safe
Open

[Swift6][Client] Make Swift 6 generator thread safe#23191
4brunu wants to merge 7 commits intoOpenAPITools:masterfrom
4brunu:feature/swift6-thread-safe

Conversation

@4brunu
Copy link
Contributor

@4brunu 4brunu commented Mar 9, 2026

[Swift6][Client] Make Swift 6 generator thread safe

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.

@jgavris (2017/07) @ehyche (2017/08) @Edubits (2017/09) @jaz-ah (2017/09) @4brunu (2019/11) @dydus0x14 (2023/06)


Summary by cubic

Make the Swift 6 client generator thread-safe by introducing OpenAPIMutex and refactoring configuration, helpers, and request tracking to use it. This removes data races and aligns with Swift concurrency across all Swift 6 client variants, including Vapor.

  • Refactors

    • Added OpenAPIMutex supporting file and included it in all generated clients; used to guard mutable state.
    • Wrapped APIConfiguration in a private State with computed properties; moved successfulStatusCodeRange, interceptors, and response serializers into State.
    • Reworked CodableHelper to guard JSON encoder/decoder and date formatters; default JSON encoder is pretty-printed.
    • Updated RequestTask and SynchronizedDictionary to use OpenAPIMutex (dictionary is now final) instead of NSRecursiveLock.
    • Marked relevant APIs and types as Sendable; Vapor beforeSend and apiWrapper are now @Sendable.
    • Updated Swift 6 templates and regenerated samples.
  • Migration

    • Vapor only: if you pass a stored closure to beforeSend, mark it @Sendable. No other changes required.

Written for commit fa52502. 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 94 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:33">
P2: Changing `dateFormatter` does not invalidate cached default JSON encoder/decoder, so later encodes/decodes can keep using an outdated date strategy.</violation>
</file>

<file name="samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift:33">
P2: Updating `dateFormatter` does not invalidate cached default JSON encoder/decoder, so encode/decode can continue using an outdated date strategy.</violation>
</file>

<file name="samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:33">
P2: Updating `dateFormatter` does not invalidate cached default coder instances, so later encode/decode calls can continue using an outdated formatter.</violation>
</file>

<file name="samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:33">
P2: Updating `dateFormatter` does not invalidate cached default JSON coders, so encode/decode may keep using an outdated date format.</violation>
</file>

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

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.

2 issues found across 14 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift:48">
P1: Mutating shared `JSONDecoder`/`JSONEncoder` strategies in place can race with concurrent encode/decode calls. Recreate default coders when `dateFormatter` changes instead of updating existing instances.</violation>
</file>

<file name="samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift:30">
P1: Updating date strategies by mutating shared default decoder/encoder instances can race with callers using previously returned decoder/encoder references. Recreate defaults when the formatter changes instead of mutating existing shared instances.</violation>
</file>

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

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.

6 issues found across 14 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:25">
P2: Rebuilding default coders by creating new `JSONDecoder`/`JSONEncoder` instances drops any existing caller customizations when `dateFormatter` is updated.</violation>
</file>

<file name="samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift:25">
P2: Rebuilding new JSONDecoder/JSONEncoder instances on date formatter changes drops existing decoder/encoder customizations made through the exposed default instances.</violation>
</file>

<file name="samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:25">
P2: Rebuilding decoder/encoder instances on `dateFormatter` updates resets previously configured `jsonDecoder`/`jsonEncoder` options (e.g., key strategies), causing silent behavior regressions.</violation>
</file>

<file name="samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:35">
P2: Recreating default JSON coders in `rebuildDefaultCoders()` drops any prior caller customization on the default encoder/decoder when `dateFormatter` changes.</violation>
</file>

<file name="samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:35">
P2: Rebuilding default coders creates new JSONEncoder/JSONDecoder instances and drops existing coder configuration when `dateFormatter` changes.</violation>
</file>

<file name="samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1" location="samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:25">
P2: Rebuilding new JSONDecoder/JSONEncoder instances in `rebuildDefaultCoders()` resets previously customized default coder settings when `dateFormatter` changes.</violation>
</file>

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

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.

26 issues found across 14 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: Encoding is now performed outside the mutex, so concurrent configuration changes can race with active encoding.</violation>

<violation number="2">
P1: Decoding is no longer protected by the mutex, allowing races with concurrent coder reconfiguration (for example `dateFormatter` updates).</violation>
</file>

<file name="samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: `encode` now executes outside synchronization, allowing races with concurrent encoder/date formatter reconfiguration.</violation>

<violation number="2">
P1: `decode` now runs outside the mutex, so coder use can race with concurrent configuration updates.</violation>
</file>

<file name="samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: `encode` uses a shared `JSONEncoder` outside the mutex, allowing concurrent encode/reconfigure races.</violation>

<violation number="2">
P1: `decode` uses a shared `JSONDecoder` outside the mutex, reintroducing a race between decoding and formatter-driven decoder reconfiguration.</violation>
</file>

<file name="samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: Encode now uses the shared `JSONEncoder` outside mutex protection, which can race with concurrent state mutation.</violation>

<violation number="2">
P1: Decode now runs outside the mutex while using a shared `JSONDecoder`, reintroducing a data race and breaking the thread-safety goal.</violation>
</file>

<file name="samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: `encode` is executed outside the mutex, so the shared default encoder can be mutated concurrently during serialization.</violation>

<violation number="2">
P1: `decode` no longer runs under the mutex, allowing concurrent mutation/use of the shared default decoder.</violation>
</file>

<file name="samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: Encoding now runs on the shared JSONEncoder outside the mutex, allowing races with concurrent state mutations.</violation>

<violation number="2">
P1: Decoding now uses the shared JSONDecoder outside the mutex, reintroducing a data race with concurrent formatter/decoder updates.</violation>
</file>

<file name="samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: `encode` now uses a shared `JSONEncoder` outside the mutex, so concurrent formatter updates can race with encoding.</violation>

<violation number="2">
P1: `decode` now uses a shared `JSONDecoder` outside the mutex, which can race with concurrent `dateFormatter` updates that mutate decoder strategy.</violation>
</file>

<file name="samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: Encoding now runs outside the mutex, which can race with concurrent encoder configuration updates.</violation>

<violation number="2">
P1: Decoding now runs outside the mutex, allowing unsynchronized concurrent access to shared decoder state.</violation>
</file>

<file name="samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: `encode` now performs encoding outside the mutex, so shared mutable `JSONEncoder` state can be accessed concurrently.</violation>

<violation number="2">
P1: `decode` now performs decoding outside the mutex, allowing concurrent access to a shared mutable `JSONDecoder` and reintroducing data-race risk.</violation>
</file>

<file name="samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: Encoding now runs outside the mutex, reintroducing a race on shared encoder state.</violation>

<violation number="2">
P1: Decoding now executes outside the mutex, allowing concurrent access to shared decoder state.</violation>
</file>

<file name="samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: `decode` now executes outside the mutex, allowing concurrent use of shared decoder state and reintroducing a thread-safety race.</violation>

<violation number="2" location="samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/CodableHelper.swift:30">
P1: `rebuildDefaultCoders` mutates shared encoder/decoder instances in place, which can race with concurrent encode/decode calls.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/swift6/CodableHelper.mustache">

<violation number="1">
P1: `encode` also uses a shared `JSONEncoder` outside `OpenAPIMutex`, allowing concurrent encode/configuration mutation on the same instance.</violation>

<violation number="2">
P1: `decode` uses a shared `JSONDecoder` outside `OpenAPIMutex`, which reintroduces a race with concurrent configuration updates (for example `dateFormatter` changes). Keep decoding inside the mutex-protected state access.</violation>
</file>

<file name="samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/CodableHelper.swift">

<violation number="1">
P1: `encode` runs on a shared `JSONEncoder` after leaving the mutex, allowing races with concurrent state mutations.</violation>

<violation number="2">
P1: `decode` now uses the shared `JSONDecoder` outside the mutex, so concurrent config updates can race with decoding.</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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant