Compare commits

...

47 Commits

Author SHA1 Message Date
William Cheng
587d4b0679 set disallowAdditionalPropertiesIfNotPresent to false as default 2023-09-13 11:24:31 +08:00
William Cheng
4260c7aaf0 Better tests for php-nextgen (#16569)
* better tests for php nextgen

* add new files
2023-09-13 10:50:29 +08:00
William Cheng
781ccae722 add go echo api tests (#16570) 2023-09-13 10:49:05 +08:00
Charles Treatman
5b4d97016a [Go] return errors that happen while unmarshalling objects (#16525)
* [Go] return errors that happen while unmarshalling objects

* Update model samples

* More updates to samples

* Update failing Go store API test to match the one that passes
2023-09-12 23:42:54 +08:00
William Cheng
9c4f6c46f7 Fix integer default value with double quote (kotlin jaxrs server generator) (#16563)
* fix integer default value with double qutoe (kotlin jaxrs)

* add enum tests

* fix typo

* update samples
2023-09-12 17:38:51 +08:00
William Cheng
a5f79a7bdc [python] Update github workflow, use debug instead of warning (#16565)
* update github workflow, use debug instead of warning

* use debug instead of warn
2023-09-12 16:55:53 +08:00
William Cheng
70543126f2 fix jaxrs sample tests (#16566) 2023-09-12 16:51:05 +08:00
martin-mfg
d6695056fe add test case for nullable parent property (#16552)
* add nullable case to spring test spec

* generate samples for changed spring input

* add nullable case to general test spec

* generate samples for changed general input

* generate samples again

* generates samples again

* re-build from new sources, generates samples again
2023-09-12 15:59:58 +08:00
Philzen
196c2b1642 [maven-generator] Do not cleanup output if spec file is unchanged and skipIfSpecIsUnchanged=true (Fixes #16490) (#16491)
* Don't delete output directory if spec is unchanged

Resolves #16490

* Fix some typos
2023-09-12 15:42:19 +08:00
Dennis Melzer
c6d355e8d4 Fix spring scope property (#16553)
* Fix spring scope property

* Adapt test files
2023-09-12 14:58:26 +08:00
William Cheng
ad589c7700 better null check for schema types (#16564) 2023-09-12 14:58:05 +08:00
Julian Vennen
cd0fde41f1 fix parent class check in ObjectSerializer (#16558) 2023-09-12 10:25:28 +08:00
Julian Vennen
8b15d4820e Use backed enums in php-nextgen (#16556) 2023-09-11 20:06:50 +08:00
devhl-labs
1901bf23ea use TypeInfoResolver (#16548) 2023-09-11 20:05:02 +08:00
Justin Black
78f3b19b58 Removes spacether (#16551)
* Update README.md

* Update team.yml

* Update pom.xml
2023-09-11 12:49:10 +08:00
William Cheng
5ee18156db [Java-Feign]: model combining properties and additionalProperties (#16546)
* [Java-Feign]: model combining properties and additionalProperties (#6146)

* update samples

---------

Co-authored-by: François Dodé <francois.dode@dawex.com>
2023-09-09 16:11:54 +08:00
William Cheng
14cfca7b06 [java][feign] Update feign client dependencies to newer version (#16545)
* update javae feign client dependencies to new versions

* update feign
2023-09-09 15:39:02 +08:00
Julian Vennen
c354bf86ff Set minimal PHP Version to ^8.1 (#16542) 2023-09-09 14:46:49 +08:00
Andrew Tran
4e15e1a813 Update pom.xml (#16544) 2023-09-09 14:40:45 +08:00
William Cheng
18df6ed85f [Spring] fix nullable map properties (#16524)
* fix map in spring generators

* fix nullable map in spring generators
2023-09-09 13:30:21 +08:00
William Cheng
128d9da8a1 update smaples 2023-09-09 11:50:36 +08:00
Andreas Johnsen
75c2e934da add omitGradleWrapper option to kotlin-server code generator (#16528)
The added option removes the wrapper part of build.gradle, enabling the generated project to be used as a sub project. The same option from kotlin client was used as reference for this change.
2023-09-09 11:40:37 +08:00
William Cheng
c614b9d9b1 [Java][resteasy] Add tests to upload files (#16534)
* add test to upload files (resteasy)

* remove resteasy tests from github workflow
2023-09-08 15:57:10 +08:00
William Cheng
026fa514c3 update java resteasy samples 2023-09-08 15:12:54 +08:00
Alex Wood
6ea8ff3a17 [java-client][resteasy] fix multipart requests (#16517)
This patch fixes two issues with the Resteasy generated client code.
The first is the usage of a deprecated method, getFormData.  The fix for
this issue was originally conceived by @peter-seitz.

The second issue was a problem in how the Content-Disposition header was
being constructed.  If we had a file named "test.txt" and were uploading
it to a field named "myFile", the Content-Disposition header should look
like

Content-Disposition: form-data; name="myFile"

Instead, the code was using the file's name (rather than the field name)
in the name directive and the header looked like

Content-Disposition: form-data; name="test.txt"

The Content-Disposition header can take an optional directive, filename,
but I have not included that here as that directive is mostly useful for
file downloads and not uploads.
2023-09-08 15:07:49 +08:00
Tom Crasset
005566c6e3 [typescript] fix: allow 'additionalProperties: true' at top level (#16526)
* fix: allow 'additionalProperties: true' at top level

* refactor: use same call as other typescript generators
2023-09-08 08:46:15 +02:00
William Cheng
dee536f7f7 import Annotated if needed (#16521) 2023-09-07 14:36:45 +08:00
William Cheng
fbff32c5d7 update java resttemplate dep to newer versions (#16523) 2023-09-07 14:36:19 +08:00
William Cheng
d1808405ca mark oneOf form parameters as optional (#16512) 2023-09-06 17:27:44 +08:00
Diego Urban
3817e40f47 [JavaSpring] Generate deprecated property, annotation and javadoc. (#16493)
* [JavaSpring] Generate deprecated annotation and doc properties

* [JavaSpring] Generate deprecated for @Schema

* [JavaSpring] Add sample folder to workflow

---------

Co-authored-by: Diego Urban <d.urban@carepay.com>
2023-09-06 15:55:15 +08:00
Artur Neumann
270238e060 [PHP] convert data to string before giving it to preg_match (#16513) 2023-09-06 15:40:07 +08:00
martin-mfg
75ac4a2f58 Fix selection of unnecessary form parameter models (#16418)
* fix idea

* add unit test

* adjust warnings about form parameters
2023-09-06 15:23:04 +08:00
Robin Jonsson
acb798b58b [JavaSpring] Call parent fluent setters from child (#16497)
* Call fluent parent setter from child pojo

This closes #16496

* Generate new samples
2023-09-06 11:43:35 +08:00
William Cheng
b1ec110aa3 go: minor refactoring (#16508) 2023-09-06 11:02:09 +08:00
jessemyers-lettuce
b34a10aee7 python: ignore long lines for model descriptions (#16518)
Descriptions can easily exceed line-length limits because they are often
extracted from doc/comments strings, which may use unexpected formatting.

Python doc strings, in particular, are likely to use newlines, which mustache
does not preserve, causing descriptions to be condensed to a single line.
2023-09-06 10:48:43 +08:00
Mike Friesen
0192baed42 Issue: #16268 (#16507)
Bug fix AWS4Auth to support query parameters and updated to use AWS SDK V2 from V1
2023-09-06 09:45:02 +08:00
Toby Archer
ecb56f1e88 Fix Elixir connection.ex middleware usage and regenerate elixir sample (#16461) 2023-09-05 21:17:37 +02:00
jessemyers-lettuce
1b32088c2d python: use isinstance instead of type() (#16516)
Use of `isinstance` is preferred (and validated by common linters).
2023-09-05 23:45:18 +08:00
William Cheng
4b7a808a9f [openapi-normalizer] add a rule to better handle openapi 3.1 spec (#16495)
* add samples

* update samples

* openapi 3.1 beta support

* update .gitignore

* fix composed schema, add oneof, allof tests in opeanpi 3.1 spec

* add allof tests, more fixes

* add null check

* update artifact id

* better null check
2023-09-05 23:27:00 +08:00
Ivan Giuliani
065b48177b [Ruby] Fix incorrect escaping of Ruby forward slashes (#16474)
* [Ruby] Test correct escaping of pattern sequences

Ruby is not correctly escaping pattern sequences containing forward
slashes in their definition. This commit adds tests that verify the
correct behaviour of the code generator.

See issue #5582.

* [Ruby] Correctly escape patterns containing forward slashes

Ruby regexs are always generated as match patterns enclosed in slash
characters (i.e. using the `/pattern/` syntax). Regular expressions
defined in the OpenAPI declaration via the `pattern` attribute follow
[ECMA 262](https://262.ecma-international.org/5.1/#sec-15.10.1) which
means they already include the correct escaping of forward slashes as
far as Ruby is concerned.

The current Ruby codegen is incorrectly escaping all forward slashes,
which ultimately causes the generated code to include additional
incorrect escape sequences which cause the generated file to have an
invalid syntax.

This commit ports the same fix introduced in #1539 for the Python
codegen, as both Ruby and Python use perl-flavored regular expressions
so they behave in the same way when it comes to escaping forward
slashes.

Fixes #5582.
2023-09-05 20:12:29 +08:00
William Cheng
8608103c9f add name mapping features to lua client generator (#16511) 2023-09-05 20:03:27 +08:00
William Cheng
a9301a6c16 [perl] Add name mapping features to the Perl client generator (#16510)
* add name mapping features to perl client generator

* update samples
2023-09-05 18:39:38 +08:00
William Cheng
29f0d22713 [Powershell] add name mapping features (#16509)
* add name mapping features to the powershell generator

* update samples
2023-09-05 15:45:03 +08:00
devhl-labs
f3eb07408d [csharp] Support source generator (#16324)
* started source generator

* copy the options

* fixed visibility

* added new sample

* discarded changes to existing samples

* discarded changes to existing samples

* build new sample

* changed package name due to file path length limit

* reverted changes to manual tests

* fixed all new manual tests

* inject contexts into api

* only one JsonConstructor

* fixed spacing

* revert samples for easier merge master

* revert unnecessary change

* fixed formatting

* build samples

* reverting unintended commit

* fixing default value

* reverting unintended commit

* removed debugging lines

* removed unnecessary diff

* address comment
2023-09-05 10:18:08 +08:00
Théophane Charbonnier
4418b59b47 [java] Microprofile - fix optional array property's default value (#16500) 2023-09-05 10:15:10 +08:00
dependabot[bot]
616e8df8d0 Bump actions/checkout from 3 to 4 (#16505)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-05 09:50:08 +08:00
William Cheng
74cd73bd6c better null check in array default value (java) (#16503) 2023-09-05 00:40:17 +08:00
1539 changed files with 122895 additions and 1373 deletions

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Test run-in-docker.sh
shell: bash

View File

@@ -13,7 +13,7 @@ jobs:
name: Gradle plugin tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:

View File

@@ -30,7 +30,7 @@ jobs:
- samples/client/petstore/java/okhttp-gson-group-parameter
- samples/client/petstore/java/webclient-swagger2
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -20,7 +20,7 @@ jobs:
os: [ubuntu-latest]
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v3
@@ -85,7 +85,7 @@ jobs:
os: [ubuntu-latest]
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Maven
uses: s4u/setup-maven-action@v1.9.0
with:

View File

@@ -13,7 +13,7 @@ jobs:
name: Maven plugin tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:

View File

@@ -15,7 +15,7 @@ jobs:
name: Misc tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '2.6'

View File

@@ -15,7 +15,7 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
@@ -53,7 +53,7 @@ jobs:
needs:
- build
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
@@ -90,7 +90,7 @@ jobs:
needs:
- build
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
@@ -129,7 +129,7 @@ jobs:
- build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:

View File

@@ -13,7 +13,7 @@ jobs:
name: Build c libcurl client
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Prepare
run: |
sudo apt-get update

View File

@@ -28,7 +28,7 @@ jobs:
tools: 'tools_openssl_x64'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: jurplel/install-qt-action@v3
with:
version: ${{ matrix.qt-version }}

View File

@@ -17,7 +17,7 @@ jobs:
name: Tests Dart
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -18,7 +18,7 @@ jobs:
# clients
- samples/client/petstore/csharp/OpenAPIClient-generichost-netstandard2.0
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: 3.1.*

View File

@@ -42,7 +42,7 @@ jobs:
- samples/server/petstore/aspnetcore-6.0-NewtonsoftFalse
- samples/server/petstore/aspnetcore-6.0-nullableReferenceTypes
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: '7.0.x'

View File

@@ -18,7 +18,7 @@ jobs:
# clients
- samples/client/echo_api/csharp-restsharp/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: '6.0.x'

View File

@@ -72,7 +72,7 @@ jobs:
# build C# API client (property, parameter name mappings)
- samples/client/petstore/csharp-restsharp-name-parameter-mappings
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: '6.0.x'

View File

@@ -29,7 +29,7 @@ jobs:
- samples/server/petstore/aspnetcore-6.0-NewtonsoftFalse
- samples/server/petstore/aspnetcore-6.0-nullableReferenceTypes
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: '6.0.x'

View File

@@ -21,7 +21,7 @@ jobs:
- samples/client/petstore/elm
- samples/openapi3/client/elm
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: jorelali/setup-elm@v5
with:
elm-version: 0.19.1

View File

@@ -26,7 +26,7 @@ jobs:
- samples/client/petstore/erlang-client/
- samples/client/petstore/erlang-proper/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
otp-version: '22.2'

View File

@@ -24,7 +24,7 @@ jobs:
- samples/server/petstore/go-api-server/
- samples/server/petstore/go-chi-server/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: "stable"

View File

@@ -21,7 +21,7 @@ jobs:
sample:
- samples/client/petstore/groovy
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -24,7 +24,7 @@ jobs:
- samples/server/petstore/haskell-servant/
- samples/client/petstore/haskell-http-client/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: haskell/actions/setup@v2
with:
# ghc-version: '8.8.4' # Exact version of ghc to use

View File

@@ -20,7 +20,7 @@ jobs:
- samples/client/echo_api/java/native
- samples/client/echo_api/java/feign-gson
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -24,7 +24,7 @@ jobs:
- samples/client/echo_api/java/feign-gson
- samples/client/echo_api/java/okhttp-gson
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -43,7 +43,6 @@ jobs:
- samples/client/petstore/java/webclient-swagger2
- samples/client/petstore/java/vertx
- samples/client/petstore/java/jersey2-java8-localdatetime
- samples/client/petstore/java/resteasy
- samples/client/petstore/java/google-api-client
- samples/client/petstore/java/rest-assured
- samples/client/petstore/java/rest-assured-jackson
@@ -63,7 +62,7 @@ jobs:
- samples/client/petstore/java/resttemplate-swagger2/
- samples/openapi3/client/petstore/java/jersey2-java8-swagger2/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
@@ -78,4 +77,4 @@ jobs:
key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }}
- name: Build
working-directory: ${{ matrix.sample }}
run: mvn clean package
run: mvn clean package

View File

@@ -21,7 +21,7 @@ jobs:
- samples/client/petstore/java/resttemplate-jakarta
- samples/client/petstore/java/webclient-jakarta
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -23,7 +23,7 @@ jobs:
- samples/server/petstore/java-helidon-server/se
version: [17]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -29,7 +29,7 @@ jobs:
- samples/server/petstore/java-play-framework-no-swagger-ui
- samples/server/petstore/java-play-framework-no-wrap-calls
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -31,7 +31,7 @@ jobs:
- samples/server/petstore/java-pkmst/
- samples/server/petstore/java-undertow/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -40,7 +40,7 @@ jobs:
- samples/server/petstore/jaxrs-cxf-non-spring-app
- samples/server/petstore/jaxrs-spec-microprofile-openapi-annotations
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -45,7 +45,7 @@ jobs:
- samples/client/petstore/spring-http-interface-reactive
- samples/client/petstore/spring-http-interface
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -15,7 +15,7 @@ jobs:
name: Tests Julia
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v1
with:
version: 1.8

View File

@@ -65,7 +65,7 @@ jobs:
- samples/client/petstore/kotlin-name-parameter-mappings
- samples/client/others/kotlin-jvm-okhttp-parameter-tests
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -28,7 +28,7 @@ jobs:
# comment out due to gradle build failure
# - samples/server/petstore/kotlin-spring-default/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -43,7 +43,7 @@ jobs:
# no build.gradle file
#- samples/server/petstore/kotlin-vertx-modelMutable
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -18,7 +18,7 @@ jobs:
# servers
- samples/server/petstore/php-laravel/lib/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP with tools
uses: shivammathur/setup-php@v2
with:

View File

@@ -18,7 +18,7 @@ jobs:
# servers
- samples/server/petstore/php-symfony/SymfonyBundle-php/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP with tools
uses: shivammathur/setup-php@v2
with:

View File

@@ -18,7 +18,7 @@ jobs:
# clients
- samples/client/echo_api/python
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.7'

View File

@@ -18,7 +18,7 @@ jobs:
# servers
- samples/server/petstore/python-aiohttp/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.7'

View File

@@ -25,7 +25,7 @@ jobs:
- samples/client/petstore/rust/
- samples/server/petstore/rust-server/
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: stable

View File

@@ -31,7 +31,7 @@ jobs:
- samples/server/petstore/scalatra
- samples/server/petstore/scala-finch # cannot be tested with jdk11
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -18,7 +18,7 @@ jobs:
# clients
- samples/openapi3/client/petstore/spring-cloud-3-with-optional
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -3,10 +3,16 @@ name: Samples Java Spring
on:
push:
paths:
# clients
- 'samples/client/petstore/spring*/**'
# servers
- 'samples/server/petstore/spring*/**'
- 'samples/openapi3/server/petstore/spring*/**'
pull_request:
paths:
# clients
- 'samples/client/petstore/spring*/**'
# servers
- 'samples/server/petstore/spring*/**'
- 'samples/openapi3/server/petstore/spring*/**'
jobs:
@@ -27,6 +33,7 @@ jobs:
- samples/openapi3/client/petstore/spring-cloud-async
- samples/openapi3/client/petstore/spring-cloud-spring-pageable
- samples/client/petstore/spring-cloud-tags
- samples/client/petstore/spring-cloud-deprecated
# servers
- samples/server/petstore/springboot
- samples/openapi3/server/petstore/springboot
@@ -49,7 +56,7 @@ jobs:
- samples/server/petstore/springboot-spring-pageable-without-j8
- samples/server/petstore/springboot-spring-pageable
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'

View File

@@ -40,7 +40,7 @@ jobs:
name: Build Swift samples
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: swift-actions/setup-swift@v1
if: ${{ matrix.os == 'ubuntu-latest' }}
with:

View File

@@ -18,7 +18,7 @@ jobs:
sample:
- samples/client/petstore/zapier
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v3
- name: Install dependencies

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'OpenAPITools' }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:

View File

@@ -18,7 +18,7 @@ jobs:
matrix:
java: [11, 17]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v3
with:

2
.gitignore vendored
View File

@@ -89,6 +89,7 @@ samples/client/petstore/cpp-restsdk/cmake_install.cmake
**/.gradle
samples/client/petstore/java/hello.txt
samples/client/petstore/java/okhttp-gson/hello.txt
samples/client/petstore/java/okhttp-gson-3.1/hello.txt
samples/client/petstore/java/jersey1/hello.txt
samples/client/petstore/java/jersey2-java8/hello.txt
samples/client/petstore/java/jersey2/hello.txt
@@ -211,6 +212,7 @@ samples/server/petstore/kotlin-server/ktor/build
samples/server/petstore/kotlin-springboot/build
samples/client/petstore/kotlin*/src/main/kotlin/test/
samples/client/petstore/kotlin*/build/
samples/server/others/kotlin-server/jaxrs-spec/build/
# haskell
.stack-work

View File

@@ -1168,7 +1168,7 @@ If you want to join the committee, please kindly apply by sending an email to te
| Perl | @wing328 (2017/07) [:heart:](https://www.patreon.com/wing328) @yue9944882 (2019/06) |
| PHP | @jebentier (2017/07), @dkarlovi (2017/07), @mandrean (2017/08), @jfastnacht (2017/09), [@ybelenko](https://github.com/ybelenko) (2018/07), @renepardon (2018/12) |
| PowerShell | @wing328 (2020/05) |
| Python | @spacether (2019/11) [:heart:][spacether sponsorship] @krjakbrjak (2023/02) |
| Python | @krjakbrjak (2023/02) |
| R | @Ramanth (2019/07) @saigiridhar21 (2019/07) |
| Ruby | @cliffano (2017/07) @zlx (2017/09) @autopp (2019/02) |
| Rust | @frol (2017/07) @farcaller (2017/08) @richardwhiuk (2019/07) @paladinzh (2020/05) @jacob-pro (2022/10) |

View File

@@ -0,0 +1,12 @@
# for csharp generichost
generatorName: csharp
outputDir: samples/client/petstore/csharp/OpenAPIClient-generichost-net6.0-nrt-useSourceGeneration
inputSpec: modules/openapi-generator/src/test/resources/3_0/csharp/petstore-with-fake-endpoints-models-for-testing-with-http-signature.yaml
library: generichost
templateDir: modules/openapi-generator/src/main/resources/csharp
additionalProperties:
packageGuid: '{321C8C3F-0156-40C1-AE42-D59761FB9B6C}'
useCompareNetObjects: true
disallowAdditionalPropertiesIfNotPresent: false
useSourceGeneration: true
packageName: UseSourceGeneration

View File

@@ -0,0 +1,6 @@
generatorName: go
outputDir: samples/client/echo_api/go
inputSpec: modules/openapi-generator/src/test/resources/3_0/echo_api.yaml
templateDir: modules/openapi-generator/src/main/resources/go
additionalProperties:
hideGenerationTimestamp: "true"

View File

@@ -0,0 +1,16 @@
generatorName: java
outputDir: samples/client/petstore/java/okhttp-gson-3.1
library: okhttp-gson
inputSpec: modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
nameMappings:
_type: underscoreType
type_: typeWithUnderscore
parameterNameMappings:
_type: underscoreType
type_: typeWithUnderscore
additionalProperties:
artifactId: petstore-okhttp-gson-31
hideGenerationTimestamp: "true"
useOneOfDiscriminatorLookup: "true"
disallowAdditionalPropertiesIfNotPresent: false

View File

@@ -4,3 +4,5 @@ inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/lua
additionalProperties:
packageName: petstore
nameMappings:
phone: mobile

View File

@@ -4,3 +4,7 @@ inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-e
templateDir: modules/openapi-generator/src/main/resources/perl
additionalProperties:
hideGenerationTimestamp: "true"
nameMappings:
NullableMessage: system_message
modelNameMappings:
DeprecatedObject: DeprecatedModel

View File

@@ -0,0 +1,6 @@
generatorName: php-nextgen
outputDir: samples/client/echo_api/php-nextgen
inputSpec: modules/openapi-generator/src/test/resources/3_0/echo_api.yaml
templateDir: modules/openapi-generator/src/main/resources/php-nextgen
additionalProperties:
hideGenerationTimestamp: "true"

View File

@@ -1,4 +1,4 @@
generatorName: php-nextgen
outputDir: samples/client/petstore/php-nextgen/OpenAPIClient-php
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
inputSpec: modules/openapi-generator/src/test/resources/3_0/php-nextgen/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/php-nextgen

View File

@@ -14,3 +14,7 @@ additionalProperties:
projectUri: https://github.com/OpenAPITools/openapi-generator
releaseNotes: 'This is a sample project'
tags: 'PetStore,powershell,sdk'
nameMappings:
name_mapping: SomethingElse
modelNameMappings:
model-mapping: NewModel

View File

@@ -0,0 +1,13 @@
generatorName: spring
library: spring-cloud
outputDir: samples/client/petstore/spring-cloud-deprecated
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-deprecated-fields.yaml
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
additionalProperties:
groupId: org.openapitools.openapi3
documentationProvider: springdoc
artifactId: spring-cloud-deprecated
interfaceOnly: "true"
singleContentTypes: "true"
hideGenerationTimestamp: "true"
useTags: "true"

View File

@@ -49,6 +49,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useCollection|Deserialize array types to Collection&lt;T&gt; instead of List&lt;T&gt;.| |false|
|useDateTimeOffset|Use DateTimeOffset to model date-time properties| |false|
|useOneOfDiscriminatorLookup|Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped.| |false|
|useSourceGeneration|Use source generation where available (only `generichost` library supports this option).| |false|
|validatable|Generates self-validatable models.| |true|
|zeroBasedEnums|Enumerations with string values will start from 0 when true, 1 when false. If not set, enumerations with string values will start from 0 if the first value is 'unknown', case insensitive.| |null|

View File

@@ -34,6 +34,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|interfaceOnly|Whether to generate only API interface stubs without the server files. This option is currently supported only when using jaxrs-spec library.| |false|
|library|library template (sub-template)|<dl><dt>**ktor**</dt><dd>ktor framework</dd><dt>**jaxrs-spec**</dt><dd>JAX-RS spec only</dd></dl>|ktor|
|modelMutable|Create mutable models| |false|
|omitGradleWrapper|Whether to omit Gradle wrapper for creating a sub project.| |false|
|packageName|Generated artifact package name.| |org.openapitools.server|
|parcelizeModels|toggle &quot;@Parcelize&quot; for generated models| |null|
|returnResponse|Whether generate API interface should return javax.ws.rs.core.Response instead of a deserialized entity. Only useful if interfaceOnly is true. This option is currently supported only when using jaxrs-spec library.| |false|

View File

@@ -520,15 +520,6 @@ public class CodeGenMojo extends AbstractMojo {
"generated-test-sources/openapi" : "generated-sources/openapi");
}
if (cleanupOutput) {
try {
FileUtils.deleteDirectory(output);
LOGGER.info("Previous run output is removed from {}", output);
} catch (IOException e) {
LOGGER.warn("Failed to clean-up output directory {}", output, e);
}
}
addCompileSourceRootIfConfigured();
try {
@@ -566,10 +557,19 @@ public class CodeGenMojo extends AbstractMojo {
}
}
if (cleanupOutput) {
try {
FileUtils.deleteDirectory(output);
LOGGER.info("Previous run output is removed from {}", output);
} catch (IOException e) {
LOGGER.warn("Failed to clean up output directory {}", output, e);
}
}
// attempt to read from config file
CodegenConfigurator configurator = CodegenConfigurator.fromFile(configurationFile);
// if a config file wasn't specified or we were unable to read it
// if a config file wasn't specified, or we were unable to read it
if (configurator == null) {
configurator = new CodegenConfigurator();
}
@@ -938,8 +938,8 @@ public class CodeGenMojo extends AbstractMojo {
/**
* Calculate openapi specification file hash. If specification is hosted on remote resource it is downloaded first
*
* @param inputSpecFile - Openapi specification input file to calculate it's hash.
* Does not taken into account if input spec is hosted on remote resource
* @param inputSpecFile - Openapi specification input file to calculate its hash.
* Does not take into account if input spec is hosted on remote resource
* @return openapi specification file hash
* @throws IOException
*/
@@ -991,8 +991,8 @@ public class CodeGenMojo extends AbstractMojo {
/**
* Get specification hash file
* @param inputSpecFile - Openapi specification input file to calculate it's hash.
* Does not taken into account if input spec is hosted on remote resource
* @param inputSpecFile - Openapi specification input file to calculate its hash.
* Does not take into account if input spec is hosted on remote resource
* @return a file with previously calculated hash
*/
private File getHashFile(File inputSpecFile) {

View File

@@ -17,6 +17,7 @@
package org.openapitools.codegen;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Ticker;
@@ -448,6 +449,7 @@ public class DefaultCodegen implements CodegenConfig {
.put("pascalcase", new CamelCaseLambda(false).generator(this))
.put("forwardslash", new ForwardSlashLambda())
.put("backslash", new BackSlashLambda())
.put("doublequote", new DoubleQuoteLambda())
.put("indented", new IndentedLambda())
.put("indented_8", new IndentedLambda(8, " ", false))
.put("indented_12", new IndentedLambda(12, " ", false))
@@ -1035,23 +1037,23 @@ public class DefaultCodegen implements CodegenConfig {
if (ModelUtils.isComposedSchema(s)) {
if (e.getKey().contains("/")) {
// if this is property schema, we also need to generate the oneOf interface model
addOneOfNameExtension((ComposedSchema) s, nOneOf);
addOneOfInterfaceModel((ComposedSchema) s, nOneOf);
addOneOfNameExtension(s, nOneOf);
addOneOfInterfaceModel(s, nOneOf);
} else {
// else this is a component schema, so we will just use that as the oneOf interface model
addOneOfNameExtension((ComposedSchema) s, n);
addOneOfNameExtension(s, n);
}
} else if (ModelUtils.isArraySchema(s)) {
Schema items = ((ArraySchema) s).getItems();
if (ModelUtils.isComposedSchema(items)) {
addOneOfNameExtension((ComposedSchema) items, nOneOf);
addOneOfInterfaceModel((ComposedSchema) items, nOneOf);
addOneOfNameExtension(items, nOneOf);
addOneOfInterfaceModel(items, nOneOf);
}
} else if (ModelUtils.isMapSchema(s)) {
Schema addProps = ModelUtils.getAdditionalProperties(s);
if (addProps != null && ModelUtils.isComposedSchema(addProps)) {
addOneOfNameExtension((ComposedSchema) addProps, nOneOf);
addOneOfInterfaceModel((ComposedSchema) addProps, nOneOf);
addOneOfNameExtension(addProps, nOneOf);
addOneOfInterfaceModel(addProps, nOneOf);
}
}
}
@@ -2273,10 +2275,9 @@ public class DefaultCodegen implements CodegenConfig {
**/
@SuppressWarnings("static-method")
public String getSchemaType(Schema schema) {
if (schema instanceof ComposedSchema) { // composed schema
ComposedSchema cs = (ComposedSchema) schema;
if (ModelUtils.isComposedSchema(schema)) { // composed schema
// Get the interfaces, i.e. the set of elements under 'allOf', 'anyOf' or 'oneOf'.
List<Schema> schemas = ModelUtils.getInterfaces(cs);
List<Schema> schemas = ModelUtils.getInterfaces(schema);
List<String> names = new ArrayList<>();
// Build a list of the schema types under each interface.
@@ -2286,12 +2287,12 @@ public class DefaultCodegen implements CodegenConfig {
names.add(getSingleSchemaType(s));
}
if (cs.getAllOf() != null) {
return toAllOfName(names, cs);
} else if (cs.getAnyOf() != null) { // anyOf
return toAnyOfName(names, cs);
} else if (cs.getOneOf() != null) { // oneOf
return toOneOfName(names, cs);
if (schema.getAllOf() != null) {
return toAllOfName(names, schema);
} else if (schema.getAnyOf() != null) { // anyOf
return toAnyOfName(names, schema);
} else if (schema.getOneOf() != null) { // oneOf
return toOneOfName(names, schema);
}
}
@@ -2327,7 +2328,7 @@ public class DefaultCodegen implements CodegenConfig {
* @return name of the allOf schema
*/
@SuppressWarnings("static-method")
public String toAllOfName(List<String> names, ComposedSchema composedSchema) {
public String toAllOfName(List<String> names, Schema composedSchema) {
Map<String, Object> exts = composedSchema.getExtensions();
if (exts != null && exts.containsKey("x-all-of-name")) {
return (String) exts.get("x-all-of-name");
@@ -2351,7 +2352,7 @@ public class DefaultCodegen implements CodegenConfig {
* @return name of the anyOf schema
*/
@SuppressWarnings("static-method")
public String toAnyOfName(List<String> names, ComposedSchema composedSchema) {
public String toAnyOfName(List<String> names, Schema composedSchema) {
return "anyOf<" + String.join(",", names) + ">";
}
@@ -2369,7 +2370,7 @@ public class DefaultCodegen implements CodegenConfig {
* @return name of the oneOf schema
*/
@SuppressWarnings("static-method")
public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
public String toOneOfName(List<String> names, Schema composedSchema) {
Map<String, Object> exts = composedSchema.getExtensions();
if (exts != null && exts.containsKey("x-one-of-name")) {
return (String) exts.get("x-one-of-name");
@@ -2674,7 +2675,7 @@ public class DefaultCodegen implements CodegenConfig {
Map<NamedSchema, CodegenProperty> schemaCodegenPropertyCache = new HashMap<>();
protected void updateModelForComposedSchema(CodegenModel m, Schema schema, Map<String, Schema> allDefinitions) {
final ComposedSchema composed = (ComposedSchema) schema;
final Schema composed = schema;
Map<String, Schema> properties = new LinkedHashMap<>();
List<String> required = new ArrayList<>();
Map<String, Schema> allProperties = new LinkedHashMap<>();
@@ -2700,17 +2701,17 @@ public class DefaultCodegen implements CodegenConfig {
if (composed.getAllOf() != null) {
int modelImplCnt = 0; // only one inline object allowed in a ComposedModel
int modelDiscriminators = 0; // only one discriminator allowed in a ComposedModel
for (Schema innerSchema : composed.getAllOf()) { // TODO need to work with anyOf, oneOf as well
if (m.discriminator == null && innerSchema.getDiscriminator() != null) {
for (Object innerSchema : composed.getAllOf()) { // TODO need to work with anyOf, oneOf as well
if (m.discriminator == null && ((Schema) innerSchema).getDiscriminator() != null) {
LOGGER.debug("discriminator is set to null (not correctly set earlier): {}", m.name);
m.setDiscriminator(createDiscriminator(m.name, innerSchema));
m.setDiscriminator(createDiscriminator(m.name, (Schema) innerSchema));
modelDiscriminators++;
}
if (innerSchema.getXml() != null) {
m.xmlPrefix = innerSchema.getXml().getPrefix();
m.xmlNamespace = innerSchema.getXml().getNamespace();
m.xmlName = innerSchema.getXml().getName();
if (((Schema) innerSchema).getXml() != null) {
m.xmlPrefix = ((Schema) innerSchema).getXml().getPrefix();
m.xmlNamespace = ((Schema) innerSchema).getXml().getNamespace();
m.xmlName = ((Schema) innerSchema).getXml().getName();
}
if (modelDiscriminators > 1) {
LOGGER.error("Allof composed schema is inheriting >1 discriminator. Only use one discriminator: {}", composed);
@@ -2747,14 +2748,14 @@ public class DefaultCodegen implements CodegenConfig {
if (composed.getAnyOf() != null) {
if (m.anyOf.contains(languageType)) {
LOGGER.warn("{} (anyOf schema) already has `{}` defined and therefore it's skipped.", m.name, languageType);
LOGGER.debug("{} (anyOf schema) already has `{}` defined and therefore it's skipped.", m.name, languageType);
} else {
m.anyOf.add(languageType);
}
} else if (composed.getOneOf() != null) {
if (m.oneOf.contains(languageType)) {
LOGGER.warn("{} (oneOf schema) already has `{}` defined and therefore it's skipped.", m.name, languageType);
LOGGER.debug("{} (oneOf schema) already has `{}` defined and therefore it's skipped.", m.name, languageType);
} else {
m.oneOf.add(languageType);
}
@@ -2888,7 +2889,7 @@ public class DefaultCodegen implements CodegenConfig {
}
protected void updateModelForObject(CodegenModel m, Schema schema) {
if (schema.getProperties() != null || schema.getRequired() != null && !(schema instanceof ComposedSchema)) {
if (schema.getProperties() != null || schema.getRequired() != null && !(ModelUtils.isComposedSchema(schema))) {
// passing null to allProperties and allRequired as there's no parent
addVars(m, unaliasPropertySchema(schema.getProperties()), schema.getRequired(), null, null);
}
@@ -2917,7 +2918,7 @@ public class DefaultCodegen implements CodegenConfig {
addAdditionPropertiesToCodeGenModel(m, schema);
m.isMap = true;
}
if (schema.getProperties() != null || schema.getRequired() != null && !(schema instanceof ComposedSchema)) {
if (schema.getProperties() != null || schema.getRequired() != null && !(ModelUtils.isComposedSchema(schema))) {
// passing null to allProperties and allRequired as there's no parent
addVars(m, unaliasPropertySchema(schema.getProperties()), schema.getRequired(), null, null);
}
@@ -3122,7 +3123,7 @@ public class DefaultCodegen implements CodegenConfig {
m.setRef(schema.get$ref());
}
if (schema instanceof ComposedSchema) {
if (ModelUtils.isComposedSchema(schema)) {
updateModelForComposedSchema(m, schema, allDefinitions);
}
@@ -3256,11 +3257,11 @@ public class DefaultCodegen implements CodegenConfig {
return cp;
}
if (ModelUtils.isComposedSchema(refSchema)) {
ComposedSchema composedSchema = (ComposedSchema) refSchema;
Schema composedSchema = refSchema;
if (composedSchema.getAllOf() != null) {
// If our discriminator is in one of the allOf schemas break when we find it
for (Schema allOf : composedSchema.getAllOf()) {
CodegenProperty cp = discriminatorFound(composedSchemaName, allOf, discPropName, visitedSchemas);
for (Object allOf : composedSchema.getAllOf()) {
CodegenProperty cp = discriminatorFound(composedSchemaName, (Schema) allOf, discPropName, visitedSchemas);
if (cp != null) {
return cp;
}
@@ -3269,9 +3270,9 @@ public class DefaultCodegen implements CodegenConfig {
if (composedSchema.getOneOf() != null && composedSchema.getOneOf().size() != 0) {
// All oneOf definitions must contain the discriminator
CodegenProperty cp = new CodegenProperty();
for (Schema oneOf : composedSchema.getOneOf()) {
String modelName = ModelUtils.getSimpleRef(oneOf.get$ref());
CodegenProperty thisCp = discriminatorFound(composedSchemaName, oneOf, discPropName, visitedSchemas);
for (Object oneOf : composedSchema.getOneOf()) {
String modelName = ModelUtils.getSimpleRef(((Schema) oneOf).get$ref());
CodegenProperty thisCp = discriminatorFound(composedSchemaName, (Schema) oneOf, discPropName, visitedSchemas);
if (thisCp == null) {
LOGGER.warn(
"'{}' defines discriminator '{}', but the referenced OneOf schema '{}' is missing {}",
@@ -3292,9 +3293,9 @@ public class DefaultCodegen implements CodegenConfig {
if (composedSchema.getAnyOf() != null && composedSchema.getAnyOf().size() != 0) {
// All anyOf definitions must contain the discriminator because a min of one must be selected
CodegenProperty cp = new CodegenProperty();
for (Schema anyOf : composedSchema.getAnyOf()) {
String modelName = ModelUtils.getSimpleRef(anyOf.get$ref());
CodegenProperty thisCp = discriminatorFound(composedSchemaName, anyOf, discPropName, visitedSchemas);
for (Object anyOf : composedSchema.getAnyOf()) {
String modelName = ModelUtils.getSimpleRef(((Schema) anyOf).get$ref());
CodegenProperty thisCp = discriminatorFound(composedSchemaName, (Schema) anyOf, discPropName, visitedSchemas);
if (thisCp == null) {
LOGGER.warn(
"'{}' defines discriminator '{}', but the referenced AnyOf schema '{}' is missing {}",
@@ -3343,11 +3344,11 @@ public class DefaultCodegen implements CodegenConfig {
Discriminator disc = new Discriminator();
if (ModelUtils.isComposedSchema(refSchema)) {
ComposedSchema composedSchema = (ComposedSchema) refSchema;
Schema composedSchema = refSchema;
if (composedSchema.getAllOf() != null) {
// If our discriminator is in one of the allOf schemas break when we find it
for (Schema allOf : composedSchema.getAllOf()) {
foundDisc = recursiveGetDiscriminator(allOf, visitedSchemas);
for (Object allOf : composedSchema.getAllOf()) {
foundDisc = recursiveGetDiscriminator((Schema) allOf, visitedSchemas);
if (foundDisc != null) {
disc.setPropertyName(foundDisc.getPropertyName());
disc.setMapping(foundDisc.getMapping());
@@ -3360,13 +3361,13 @@ public class DefaultCodegen implements CodegenConfig {
Integer hasDiscriminatorCnt = 0;
Integer hasNullTypeCnt = 0;
Set<String> discriminatorsPropNames = new HashSet<>();
for (Schema oneOf : composedSchema.getOneOf()) {
if (ModelUtils.isNullType(oneOf)) {
for (Object oneOf : composedSchema.getOneOf()) {
if (ModelUtils.isNullType((Schema) oneOf)) {
// The null type does not have a discriminator. Skip.
hasNullTypeCnt++;
continue;
}
foundDisc = recursiveGetDiscriminator(oneOf, visitedSchemas);
foundDisc = recursiveGetDiscriminator((Schema) oneOf, visitedSchemas);
if (foundDisc != null) {
discriminatorsPropNames.add(foundDisc.getPropertyName());
hasDiscriminatorCnt++;
@@ -3389,13 +3390,13 @@ public class DefaultCodegen implements CodegenConfig {
Integer hasDiscriminatorCnt = 0;
Integer hasNullTypeCnt = 0;
Set<String> discriminatorsPropNames = new HashSet<>();
for (Schema anyOf : composedSchema.getAnyOf()) {
if (ModelUtils.isNullType(anyOf)) {
for (Object anyOf : composedSchema.getAnyOf()) {
if (ModelUtils.isNullType((Schema) anyOf)) {
// The null type does not have a discriminator. Skip.
hasNullTypeCnt++;
continue;
}
foundDisc = recursiveGetDiscriminator(anyOf, visitedSchemas);
foundDisc = recursiveGetDiscriminator((Schema) anyOf, visitedSchemas);
if (foundDisc != null) {
discriminatorsPropNames.add(foundDisc.getPropertyName());
hasDiscriminatorCnt++;
@@ -3430,7 +3431,7 @@ public class DefaultCodegen implements CodegenConfig {
* @param c The ComposedSchema that contains the discriminator and oneOf/anyOf schemas
* @return the list of oneOf and anyOf MappedModel that need to be added to the discriminator map
*/
protected List<MappedModel> getOneOfAnyOfDescendants(String composedSchemaName, String discPropName, ComposedSchema c) {
protected List<MappedModel> getOneOfAnyOfDescendants(String composedSchemaName, String discPropName, Schema c) {
ArrayList<List<Schema>> listOLists = new ArrayList<>();
listOLists.add(c.getOneOf());
listOLists.add(c.getAnyOf());
@@ -3510,8 +3511,7 @@ public class DefaultCodegen implements CodegenConfig {
}
Schema child = schemas.get(childName);
if (ModelUtils.isComposedSchema(child)) {
ComposedSchema composedChild = (ComposedSchema) child;
List<Schema> parents = composedChild.getAllOf();
List<Schema> parents = child.getAllOf();
if (parents != null) {
for (Schema parent : parents) {
String ref = parent.get$ref();
@@ -3624,7 +3624,7 @@ public class DefaultCodegen implements CodegenConfig {
}
// if there are composed oneOf/anyOf schemas, add them to this discriminator
if (ModelUtils.isComposedSchema(schema) && !this.getLegacyDiscriminatorBehavior()) {
List<MappedModel> otherDescendants = getOneOfAnyOfDescendants(schemaName, discriminatorPropertyName, (ComposedSchema) schema);
List<MappedModel> otherDescendants = getOneOfAnyOfDescendants(schemaName, discriminatorPropertyName, schema);
for (MappedModel otherDescendant : otherDescendants) {
if (!uniqueDescendants.contains(otherDescendant)) {
uniqueDescendants.add(otherDescendant);
@@ -3658,15 +3658,18 @@ public class DefaultCodegen implements CodegenConfig {
* @param visitedSchemas circuit-breaker - the schemas with which the method was called before for recursive structures
*/
protected void addProperties(Map<String, Schema> properties, List<String> required, Schema schema, Set<Schema> visitedSchemas) {
if (schema == null) {
return;
}
if (!visitedSchemas.add(schema)) {
return;
}
if (schema instanceof ComposedSchema) {
ComposedSchema composedSchema = (ComposedSchema) schema;
if (ModelUtils.isComposedSchema(schema)) {
if (composedSchema.getAllOf() != null) {
for (Schema component : composedSchema.getAllOf()) {
addProperties(properties, required, component, visitedSchemas);
if (schema.getAllOf() != null) {
for (Object component : schema.getAllOf()) {
addProperties(properties, required, (Schema) component, visitedSchemas);
}
}
@@ -3674,15 +3677,15 @@ public class DefaultCodegen implements CodegenConfig {
required.addAll(schema.getRequired());
}
if (composedSchema.getOneOf() != null) {
for (Schema component : composedSchema.getOneOf()) {
addProperties(properties, required, component, visitedSchemas);
if (schema.getOneOf() != null) {
for (Object component : schema.getOneOf()) {
addProperties(properties, required, (Schema) component, visitedSchemas);
}
}
if (composedSchema.getAnyOf() != null) {
for (Schema component : composedSchema.getAnyOf()) {
addProperties(properties, required, component, visitedSchemas);
if (schema.getAnyOf() != null) {
for (Object component : schema.getAnyOf()) {
addProperties(properties, required, (Schema) component, visitedSchemas);
}
}
@@ -3766,10 +3769,11 @@ public class DefaultCodegen implements CodegenConfig {
if (Boolean.FALSE.equals(p.getNullable())) {
LOGGER.warn("Schema '{}' is any type, which includes the 'null' value. 'nullable' cannot be set to 'false'", p.getName());
}
ComposedSchema composedSchema = p instanceof ComposedSchema
? (ComposedSchema) p
: null;
property.isNullable = property.isNullable || composedSchema == null || composedSchema.getAllOf() == null || composedSchema.getAllOf().size() == 0;
property.isNullable = property.isNullable ||
!(ModelUtils.isComposedSchema(p)) ||
p.getAllOf() == null ||
p.getAllOf().size() == 0;
if (languageSpecificPrimitives.contains(property.dataType)) {
property.isPrimitiveType = true;
}
@@ -5746,7 +5750,7 @@ public class DefaultCodegen implements CodegenConfig {
* @param model codegen model
* @param modelName model name
*/
protected void addImport(ComposedSchema composed, Schema childSchema, CodegenModel model, String modelName ) {
protected void addImport(Schema composed, Schema childSchema, CodegenModel model, String modelName ) {
if (composed == null || childSchema == null) {
return;
}
@@ -6925,6 +6929,13 @@ public class DefaultCodegen implements CodegenConfig {
LOGGER.debug("debugging fromRequestBodyToFormParameters= {}", body);
Schema schema = ModelUtils.getSchemaFromRequestBody(body);
schema = ModelUtils.getReferencedSchema(this.openAPI, schema);
if(ModelUtils.isMapSchema(schema)) {
LOGGER.error("Form parameters with additionalProperties are not supported by OpenAPI Generator. Please report the issue to https://github.com/openapitools/openapi-generator if you need help.");
}
if(ModelUtils.isArraySchema(schema)) {
LOGGER.error("Array form parameters are not supported by OpenAPI Generator. Please report the issue to https://github.com/openapitools/openapi-generator if you need help.");
}
List<String> allRequired = new ArrayList<>();
Map<String, Schema> properties = new LinkedHashMap<>();
// this traverses a composed schema and extracts all properties in each schema into properties
@@ -6933,6 +6944,8 @@ public class DefaultCodegen implements CodegenConfig {
// https://github.com/OpenAPITools/openapi-generator/issues/10415
addProperties(properties, allRequired, schema, new HashSet<>());
boolean isOneOfOrAnyOf = ModelUtils.isOneOf(schema) || ModelUtils.isAnyOf(schema);
if (!properties.isEmpty()) {
for (Map.Entry<String, Schema> entry : properties.entrySet()) {
CodegenParameter codegenParameter;
@@ -6940,14 +6953,14 @@ public class DefaultCodegen implements CodegenConfig {
// value => property schema
String propertyName = entry.getKey();
Schema propertySchema = entry.getValue();
if (ModelUtils.isMapSchema(propertySchema)) {
LOGGER.error("Map of form parameters not supported. Please report the issue to https://github.com/openapitools/openapi-generator if you need help.");
continue;
}
codegenParameter = fromFormProperty(propertyName, propertySchema, imports);
// Set 'required' flag defined in the schema element
if (!codegenParameter.required && schema.getRequired() != null) {
if (isOneOfOrAnyOf) {
// for oneOf/anyOf, mark all the properties collected from the sub-schemas as optional
// so that users can choose which property to include in the form parameters
codegenParameter.required = false;
} else if (!codegenParameter.required && schema.getRequired() != null) {
// Set 'required' flag defined in the schema element
codegenParameter.required = schema.getRequired().contains(entry.getKey());
} else if (!codegenParameter.required) {
// Set 'required' flag for properties declared inside the allOf
@@ -7920,12 +7933,12 @@ public class DefaultCodegen implements CodegenConfig {
/**
* Add "x-one-of-name" extension to a given oneOf schema (assuming it has at least 1 oneOf elements)
*
* @param s schema to add the extension to
* @param name name of the parent oneOf schema
* @param schema schema to add the extension to
* @param name name of the parent oneOf schema
*/
public void addOneOfNameExtension(ComposedSchema s, String name) {
if (s.getOneOf() != null && s.getOneOf().size() > 0) {
s.addExtension("x-one-of-name", name);
public void addOneOfNameExtension(Schema schema, String name) {
if (schema.getOneOf() != null && schema.getOneOf().size() > 0) {
schema.addExtension("x-one-of-name", name);
}
}
@@ -7935,7 +7948,7 @@ public class DefaultCodegen implements CodegenConfig {
* @param cs ComposedSchema object to create as interface model
* @param type name to use for the generated interface model
*/
public void addOneOfInterfaceModel(ComposedSchema cs, String type) {
public void addOneOfInterfaceModel(Schema cs, String type) {
if (cs.getOneOf() == null) {
return;
}
@@ -7944,9 +7957,9 @@ public class DefaultCodegen implements CodegenConfig {
cm.setDiscriminator(createDiscriminator("", cs));
for (Schema o : Optional.ofNullable(cs.getOneOf()).orElse(Collections.emptyList())) {
if (o.get$ref() == null) {
if (cm.discriminator != null && o.get$ref() == null) {
for (Object o : Optional.ofNullable(cs.getOneOf()).orElse(Collections.emptyList())) {
if (((Schema) o).get$ref() == null) {
if (cm.discriminator != null && ((Schema) o).get$ref() == null) {
// OpenAPI spec states that inline objects should not be considered when discriminator is used
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminatorObject
LOGGER.warn("Ignoring inline object in oneOf definition of {}, since discriminator is used", type);
@@ -7955,7 +7968,7 @@ public class DefaultCodegen implements CodegenConfig {
}
continue;
}
cm.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref())));
cm.oneOf.add(toModelName(ModelUtils.getSimpleRef(((Schema) o).get$ref())));
}
cm.name = type;
cm.classname = type;
@@ -8126,7 +8139,7 @@ public class DefaultCodegen implements CodegenConfig {
}
private CodegenComposedSchemas getComposedSchemas(Schema schema) {
if (!(schema instanceof ComposedSchema) && schema.getNot() == null) {
if (!(ModelUtils.isComposedSchema(schema)) && schema.getNot() == null) {
return null;
}
Schema notSchema = schema.getNot();
@@ -8137,11 +8150,10 @@ public class DefaultCodegen implements CodegenConfig {
List<CodegenProperty> allOf = new ArrayList<>();
List<CodegenProperty> oneOf = new ArrayList<>();
List<CodegenProperty> anyOf = new ArrayList<>();
if (schema instanceof ComposedSchema) {
ComposedSchema cs = (ComposedSchema) schema;
allOf = getComposedProperties(cs.getAllOf(), "all_of");
oneOf = getComposedProperties(cs.getOneOf(), "one_of");
anyOf = getComposedProperties(cs.getAnyOf(), "any_of");
if (ModelUtils.isComposedSchema(schema)) {
allOf = getComposedProperties(schema.getAllOf(), "all_of");
oneOf = getComposedProperties(schema.getOneOf(), "one_of");
anyOf = getComposedProperties(schema.getAnyOf(), "any_of");
}
return new CodegenComposedSchemas(
allOf,

View File

@@ -58,6 +58,7 @@ import org.openapitools.codegen.utils.ImplementationVersion;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.ProcessUtils;
import org.openapitools.codegen.utils.URLPathUtils;
import org.openapitools.codegen.utils.SemVer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -262,6 +263,10 @@ public class DefaultGenerator implements Generator {
// normalize the spec
try {
if (config.getUseOpenAPINormalizer()) {
SemVer version = new SemVer(openAPI.getOpenapi());
if (version.atLeast("3.1.0")) {
config.openapiNormalizer().put("NORMALIZE_31SPEC", "true");
}
OpenAPINormalizer openapiNormalizer = new OpenAPINormalizer(openAPI, config.openapiNormalizer());
openapiNormalizer.normalize();
}

View File

@@ -216,32 +216,30 @@ public class InlineModelResolver {
return true;
}
}
if (schema instanceof ComposedSchema) {
if (ModelUtils.isComposedSchema(schema)) {
// allOf, anyOf, oneOf
ComposedSchema m = (ComposedSchema) schema;
boolean isSingleAllOf = m.getAllOf() != null && m.getAllOf().size() == 1;
boolean isReadOnly = m.getReadOnly() != null && m.getReadOnly();
boolean isNullable = m.getNullable() != null && m.getNullable();
boolean isSingleAllOf = schema.getAllOf() != null && schema.getAllOf().size() == 1;
boolean isReadOnly = schema.getReadOnly() != null && schema.getReadOnly();
boolean isNullable = schema.getNullable() != null && schema.getNullable();
if (isSingleAllOf && (isReadOnly || isNullable)) {
// Check if this composed schema only contains an allOf and a readOnly or nullable.
ComposedSchema c = new ComposedSchema();
c.setAllOf(m.getAllOf());
c.setReadOnly(m.getReadOnly());
c.setNullable(m.getNullable());
if (m.equals(c)) {
return isModelNeeded(m.getAllOf().get(0), visitedSchemas);
c.setAllOf(schema.getAllOf());
c.setReadOnly(schema.getReadOnly());
c.setNullable(schema.getNullable());
if (schema.equals(c)) {
return isModelNeeded((Schema) schema.getAllOf().get(0), visitedSchemas);
}
} else if (isSingleAllOf && StringUtils.isNotEmpty(m.getAllOf().get(0).get$ref())) {
} else if (isSingleAllOf && StringUtils.isNotEmpty(((Schema) schema.getAllOf().get(0)).get$ref())) {
// single allOf and it's a ref
return isModelNeeded(m.getAllOf().get(0), visitedSchemas);
return isModelNeeded((Schema) schema.getAllOf().get(0), visitedSchemas);
}
if (m.getAllOf() != null && !m.getAllOf().isEmpty()) {
if (schema.getAllOf() != null && !schema.getAllOf().isEmpty()) {
// check to ensure at least one of the allOf item is model
for (Schema inner : m.getAllOf()) {
if (isModelNeeded(ModelUtils.getReferencedSchema(openAPI, inner), visitedSchemas)) {
for (Object inner : schema.getAllOf()) {
if (isModelNeeded(ModelUtils.getReferencedSchema(openAPI, (Schema) inner), visitedSchemas)) {
return true;
}
}
@@ -249,10 +247,10 @@ public class InlineModelResolver {
return false;
}
if (m.getAnyOf() != null && !m.getAnyOf().isEmpty()) {
if (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty()) {
return true;
}
if (m.getOneOf() != null && !m.getOneOf().isEmpty()) {
if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) {
return true;
}
}
@@ -273,7 +271,7 @@ public class InlineModelResolver {
// any to catch OpenAPI violations
if (isModelNeeded(schema) || "object".equals(schema.getType()) ||
schema.getProperties() != null || schema.getAdditionalProperties() != null ||
schema instanceof ComposedSchema) {
ModelUtils.isComposedSchema(schema)) {
LOGGER.error("Illegal schema found with $ref combined with other properties," +
" no properties should be defined alongside a $ref:\n " + schema.toString());
}
@@ -295,13 +293,13 @@ public class InlineModelResolver {
// If this schema should be split into its own model, do so
Schema refSchema = this.makeSchemaInComponents(schemaName, prop);
props.put(propName, refSchema);
} else if (prop instanceof ComposedSchema) {
ComposedSchema m = (ComposedSchema) prop;
if (m.getAllOf() != null && m.getAllOf().size() == 1 &&
!(m.getAllOf().get(0).getType() == null || "object".equals(m.getAllOf().get(0).getType()))) {
} else if (ModelUtils.isComposedSchema(prop)) {
if (prop.getAllOf() != null && prop.getAllOf().size() == 1 &&
!(((Schema) prop.getAllOf().get(0)).getType() == null ||
"object".equals(((Schema) prop.getAllOf().get(0)).getType()))) {
// allOf with only 1 type (non-model)
LOGGER.info("allOf schema used by the property `{}` replaced by its only item (a type)", propName);
props.put(propName, m.getAllOf().get(0));
props.put(propName, (Schema) prop.getAllOf().get(0));
}
}
}
@@ -357,71 +355,69 @@ public class InlineModelResolver {
}
}
// Check allOf, anyOf, oneOf for inline models
if (schema instanceof ComposedSchema) {
ComposedSchema m = (ComposedSchema) schema;
if (m.getAllOf() != null) {
if (ModelUtils.isComposedSchema(schema)) {
if (schema.getAllOf() != null) {
List<Schema> newAllOf = new ArrayList<Schema>();
boolean atLeastOneModel = false;
for (Schema inner : m.getAllOf()) {
String schemaName = resolveModelName(inner.getTitle(), modelPrefix + "_allOf");
for (Object inner : schema.getAllOf()) {
String schemaName = resolveModelName(((Schema) inner).getTitle(), modelPrefix + "_allOf");
// Recurse to create $refs for inner models
gatherInlineModels(inner, schemaName);
if (isModelNeeded(inner)) {
gatherInlineModels((Schema) inner, schemaName);
if (isModelNeeded((Schema) inner)) {
if (Boolean.TRUE.equals(this.refactorAllOfInlineSchemas)) {
Schema refSchema = this.makeSchemaInComponents(schemaName, inner);
Schema refSchema = this.makeSchemaInComponents(schemaName, (Schema) inner);
newAllOf.add(refSchema); // replace with ref
atLeastOneModel = true;
} else { // do not refactor allOf inline schemas
newAllOf.add(inner);
newAllOf.add((Schema) inner);
atLeastOneModel = true;
}
} else {
newAllOf.add(inner);
newAllOf.add((Schema) inner);
}
}
if (atLeastOneModel) {
m.setAllOf(newAllOf);
schema.setAllOf(newAllOf);
} else {
// allOf is just one or more types only so do not generate the inline allOf model
if (m.getAllOf().size() == 1) {
if (schema.getAllOf().size() == 1) {
// handle earlier in this function when looping through properties
} else if (m.getAllOf().size() > 1) {
} else if (schema.getAllOf().size() > 1) {
LOGGER.warn("allOf schema `{}` containing multiple types (not model) is not supported at the moment.", schema.getName());
} else {
LOGGER.error("allOf schema `{}` contains no items.", schema.getName());
}
}
}
if (m.getAnyOf() != null) {
if (schema.getAnyOf() != null) {
List<Schema> newAnyOf = new ArrayList<Schema>();
for (Schema inner : m.getAnyOf()) {
String schemaName = resolveModelName(inner.getTitle(), modelPrefix + "_anyOf");
for (Object inner : schema.getAnyOf()) {
String schemaName = resolveModelName(((Schema) inner).getTitle(), modelPrefix + "_anyOf");
// Recurse to create $refs for inner models
gatherInlineModels(inner, schemaName);
if (isModelNeeded(inner)) {
Schema refSchema = this.makeSchemaInComponents(schemaName, inner);
gatherInlineModels((Schema) inner, schemaName);
if (isModelNeeded((Schema) inner)) {
Schema refSchema = this.makeSchemaInComponents(schemaName, (Schema) inner);
newAnyOf.add(refSchema); // replace with ref
} else {
newAnyOf.add(inner);
newAnyOf.add((Schema) inner);
}
}
m.setAnyOf(newAnyOf);
schema.setAnyOf(newAnyOf);
}
if (m.getOneOf() != null) {
if (schema.getOneOf() != null) {
List<Schema> newOneOf = new ArrayList<Schema>();
for (Schema inner : m.getOneOf()) {
String schemaName = resolveModelName(inner.getTitle(), modelPrefix + "_oneOf");
for (Object inner : schema.getOneOf()) {
String schemaName = resolveModelName(((Schema) inner).getTitle(), modelPrefix + "_oneOf");
// Recurse to create $refs for inner models
gatherInlineModels(inner, schemaName);
if (isModelNeeded(inner)) {
Schema refSchema = this.makeSchemaInComponents(schemaName, inner);
gatherInlineModels((Schema) inner, schemaName);
if (isModelNeeded((Schema) inner)) {
Schema refSchema = this.makeSchemaInComponents(schemaName, (Schema) inner);
newOneOf.add(refSchema); // replace with ref
} else {
newOneOf.add(inner);
newOneOf.add((Schema) inner);
}
}
m.setOneOf(newOneOf);
schema.setOneOf(newOneOf);
}
}
// Check not schema
@@ -638,11 +634,10 @@ public class InlineModelResolver {
} else if (ModelUtils.isOneOf(model)) { // contains oneOf only
gatherInlineModels(model, modelName);
} else if (ModelUtils.isComposedSchema(model)) {
ComposedSchema m = (ComposedSchema) model;
// inline child schemas
flattenComposedChildren(modelName + "_allOf", m.getAllOf(), !Boolean.TRUE.equals(this.refactorAllOfInlineSchemas));
flattenComposedChildren(modelName + "_anyOf", m.getAnyOf(), false);
flattenComposedChildren(modelName + "_oneOf", m.getOneOf(), false);
flattenComposedChildren(modelName + "_allOf", model.getAllOf(), !Boolean.TRUE.equals(this.refactorAllOfInlineSchemas));
flattenComposedChildren(modelName + "_anyOf", model.getAnyOf(), false);
flattenComposedChildren(modelName + "_oneOf", model.getOneOf(), false);
} else {
gatherInlineModels(model, modelName);
}

View File

@@ -19,6 +19,7 @@ package org.openapitools.codegen;
import io.swagger.v3.oas.models.*;
import io.swagger.v3.oas.models.callbacks.Callback;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
@@ -87,6 +88,9 @@ public class OpenAPINormalizer {
// the allOf contains a new schema containing the properties in the top level
final String REFACTOR_ALLOF_WITH_PROPERTIES_ONLY = "REFACTOR_ALLOF_WITH_PROPERTIES_ONLY";
// when set to true, normalize OpenAPI 3.1 spec to make it work with the generator
final String NORMALIZE_31SPEC = "NORMALIZE_31SPEC";
// ============= end of rules =============
/**
@@ -115,6 +119,7 @@ public class OpenAPINormalizer {
ruleNames.add(SET_TAGS_FOR_ALL_OPERATIONS);
ruleNames.add(ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE);
ruleNames.add(REFACTOR_ALLOF_WITH_PROPERTIES_ONLY);
ruleNames.add(NORMALIZE_31SPEC);
// rules that are default to true
rules.put(SIMPLIFY_ONEOF_ANYOF, true);
@@ -148,7 +153,7 @@ public class OpenAPINormalizer {
// loop through all the rules
for (Map.Entry<String, String> rule : inputRules.entrySet()) {
LOGGER.info("processing rule {} => {}", rule.getKey(), rule.getValue());
LOGGER.debug("processing rule {} => {}", rule.getKey(), rule.getValue());
if (!ruleNames.contains(rule.getKey())) { // invalid rule name
LOGGER.warn("Invalid openapi-normalizer rule name: ", rule.getKey());
} else if (enableAll) {
@@ -247,11 +252,13 @@ public class OpenAPINormalizer {
} else if (mediaType.getSchema() == null) {
continue;
} else {
normalizeSchema(mediaType.getSchema(), new HashSet<>());
Schema newSchema = normalizeSchema(mediaType.getSchema(), new HashSet<>());
mediaType.setSchema(newSchema);
}
}
}
/**
* Normalizes schemas in RequestBody
*
@@ -291,7 +298,8 @@ public class OpenAPINormalizer {
if (parameter.getSchema() == null) {
continue;
} else {
normalizeSchema(parameter.getSchema(), new HashSet<>());
Schema newSchema = normalizeSchema(parameter.getSchema(), new HashSet<>());
parameter.setSchema(newSchema);
}
}
}
@@ -312,10 +320,29 @@ public class OpenAPINormalizer {
continue;
} else {
normalizeContent(responsesEntry.getValue().getContent());
normalizeHeaders(responsesEntry.getValue().getHeaders());
}
}
}
/**
* Normalizes schemas in headers
*
* @param headers a map of headers
*/
private void normalizeHeaders(Map<String, Header> headers) {
if (headers == null || headers.isEmpty()) {
return;
}
for (String headerKey : headers.keySet()) {
Header h = headers.get(headerKey);
Schema updatedHeader = normalizeSchema(h.getSchema(), new HashSet<>());
h.setSchema(updatedHeader);
}
}
/**
* Normalizes schemas in components
*/
@@ -408,7 +435,7 @@ public class OpenAPINormalizer {
} else if (schema instanceof IntegerSchema) {
normalizeIntegerSchema(schema, visitedSchemas);
} else if (schema instanceof Schema) {
normalizeSchemaWithOnlyProperties(schema, visitedSchemas);
return normalizeSimpleSchema(schema, visitedSchemas);
} else {
throw new RuntimeException("Unknown schema type found in normalizer: " + schema);
}
@@ -416,6 +443,10 @@ public class OpenAPINormalizer {
return schema;
}
private Schema normalizeSimpleSchema(Schema schema, Set<Schema> visitedSchemas) {
return processNormalize31Spec(schema, visitedSchemas);
}
private void normalizeBooleanSchema(Schema schema, Set<Schema> visitedSchemas) {
processSimplifyBooleanEnum(schema);
}
@@ -424,10 +455,6 @@ public class OpenAPINormalizer {
processAddUnsignedToIntegerWithInvalidMaxValue(schema);
}
private void normalizeSchemaWithOnlyProperties(Schema schema, Set<Schema> visitedSchemas) {
// normalize non-composed schema (e.g. schema with only properties)
}
private void normalizeProperties(Map<String, Schema> properties, Set<Schema> visitedSchemas) {
if (properties == null) {
return;
@@ -670,9 +697,9 @@ public class OpenAPINormalizer {
/**
* Check if the schema is of type 'null'
*
* <p>
* Return true if the schema's type is 'null' or not specified
*
*
* @param schema Schema
*/
private boolean isNullTypeSchema(Schema schema) {
@@ -803,7 +830,7 @@ public class OpenAPINormalizer {
}
}
/*
/**
* When set to true, refactor schema with allOf and properties in the same level to a schema with allOf only and
* the allOf contains a new schema containing the properties in the top level.
*
@@ -844,5 +871,75 @@ public class OpenAPINormalizer {
return schema;
}
/**
* When set to true, normalize schema so that it works well with the generator.
*
* @param schema Schema
* @param visitedSchemas a set of visited schemas
* @return Schema
*/
private Schema processNormalize31Spec(Schema schema, Set<Schema> visitedSchemas) {
if (!getRule(NORMALIZE_31SPEC)) {
return schema;
}
if (schema == null || schema.getTypes() == null) {
return null;
}
// process null
if (schema.getTypes().contains("null")) {
schema.setNullable(true);
schema.getTypes().remove("null");
}
// only one item (type) left
if (schema.getTypes().size() == 1) {
String type = String.valueOf(schema.getTypes().iterator().next());
if ("array".equals(type)) {
ArraySchema as = new ArraySchema();
as.setXml(schema.getXml());
// `items` is also a json schema
if (StringUtils.isNotEmpty(schema.getItems().get$ref())) {
Schema ref = new Schema();
ref.set$ref(schema.getItems().get$ref());
as.setItems(ref);
} else { // inline schema (e.g. model, string, etc)
Schema updatedItems = normalizeSchema(schema.getItems(), visitedSchemas);
as.setItems(updatedItems);
}
return as;
} else { // other primitive type such as string
// set type (3.0 spec) directly
schema.setType(type);
}
} else { // more than 1 item
// convert to anyOf and keep all other attributes (e.g. nullable, description)
// the same. No need to handle null as it should have been removed at this point.
for (Object type : schema.getTypes()) {
switch (String.valueOf(type)) {
case "string":
schema.addAnyOfItem(new StringSchema());
break;
case "integer":
schema.addAnyOfItem(new IntegerSchema());
break;
case "number":
schema.addAnyOfItem(new NumberSchema());
break;
case "boolean":
schema.addAnyOfItem(new BooleanSchema());
break;
default:
LOGGER.error("Type {} not yet supported in openapi-normalizer to process OpenAPI 3.1 spec with multiple types.");
LOGGER.error("Please report the issue via https://github.com/OpenAPITools/openapi-generator/issues/new/.");
}
}
}
return schema;
}
// ===================== end of rules =====================
}

View File

@@ -59,6 +59,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
protected boolean returnICollection = false;
protected boolean netCoreProjectFileFlag = false;
protected boolean nullReferenceTypesFlag = false;
protected boolean useSourceGeneration = false;
protected String modelPropertyNaming = CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.PascalCase.name();
@@ -416,12 +417,15 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
.put("required", new RequiredParameterLambda())
.put("optional", new OptionalParameterLambda().generator(this))
.put("joinWithComma", new JoinWithCommaLambda())
.put("joinLinesWithComma", new JoinWithCommaLambda(false, "\n", ",\n"))
.put("trimLineBreaks", new TrimLineBreaksLambda())
.put("trimTrailingWithNewLine", new TrimTrailingWhiteSpaceLambda(true))
.put("trimTrailing", new TrimTrailingWhiteSpaceLambda(false))
.put("first", new FirstLambda(" "))
.put("firstDot", new FirstLambda("\\."))
.put("indent3", new IndentedLambda(12, " ", false))
.put("indent4", new IndentedLambda(16, " ", false));
.put("indent4", new IndentedLambda(16, " ", false))
.put("uniqueLinesWithNewLine", new UniqueLambda("\n", true));
}
@Override
@@ -1350,6 +1354,14 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
return this.nullReferenceTypesFlag;
}
public void setUseSourceGeneration(final Boolean useSourceGeneration) {
this.useSourceGeneration = useSourceGeneration;
}
public boolean getUseSourceGeneration() {
return this.useSourceGeneration;
}
public void setInterfacePrefix(final String interfacePrefix) {
this.interfacePrefix = interfacePrefix;
}

View File

@@ -1062,7 +1062,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
} else { // has default value
return toArrayDefaultValue(cp, schema);
}
} else if (ModelUtils.isMapSchema(schema) && !(schema instanceof ComposedSchema)) {
} else if (ModelUtils.isMapSchema(schema) && !(ModelUtils.isComposedSchema(schema))) {
if (schema.getProperties() != null && schema.getProperties().size() > 0) {
// object is complex object with free-form additional properties
if (schema.getDefault() != null) {
@@ -1349,8 +1349,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
if (example == null) {
example = "null";
} else if (Boolean.TRUE.equals(p.isArray)) {
if (p.items.defaultValue != null) {
if (p.items != null && p.items.defaultValue != null) {
String innerExample;
if ("String".equals(p.items.dataType)) {
innerExample = "\"" + p.items.defaultValue + "\"";
@@ -1646,11 +1645,11 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
.map(Schema::getProperties))
.forEach(schemas -> schemas.replaceAll(
(name, s) -> Stream.of(s)
.filter(schema -> schema instanceof ComposedSchema)
.map(schema -> (ComposedSchema) schema)
.filter(schema -> Objects.nonNull(schema.getAnyOf()))
.flatMap(schema -> schema.getAnyOf().stream())
.filter(schema -> Objects.nonNull(schema.getEnum()))
.filter(schema -> ModelUtils.isComposedSchema((Schema) schema))
//.map(schema -> (ComposedSchema) schema)
.filter(schema -> Objects.nonNull(((Schema) schema).getAnyOf()))
.flatMap(schema -> ((Schema) schema).getAnyOf().stream())
.filter(schema -> Objects.nonNull(((Schema) schema).getEnum()))
.findFirst()
.orElse((Schema) s)));
}

View File

@@ -1143,7 +1143,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
* ModelUtils.isMapSchema
* In other generators, isMap is true for all type object schemas
*/
if (schema.getProperties() != null || schema.getRequired() != null && !(schema instanceof ComposedSchema)) {
if (schema.getProperties() != null || schema.getRequired() != null && !(ModelUtils.isComposedSchema(schema))) {
// passing null to allProperties and allRequired as there's no parent
addVars(m, unaliasPropertySchema(schema.getProperties()), schema.getRequired(), null, null);
}

View File

@@ -529,7 +529,7 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
}
example += ")";
} else {
LOGGER.warn("Type {} not handled properly in toExampleValue", schema.getType());
LOGGER.debug("Type {} not handled properly in toExampleValue", schema.getType());
}
if (ModelUtils.isStringSchema(schema)) {
@@ -591,7 +591,7 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
// type is a model class, e.g. User
example = this.packageName + "." + type + "()";
} else {
LOGGER.warn("Type {} not handled properly in setParameterExampleValue", type);
LOGGER.debug("Type {} not handled properly in setParameterExampleValue", type);
}
if (example == null) {
@@ -1747,6 +1747,7 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
hasModelsToImport = false;
boolean importAnnotated = false;
TreeSet<String> typingImports = new TreeSet<>();
TreeSet<String> pydanticImports = new TreeSet<>();
TreeSet<String> datetimeImports = new TreeSet<>();
@@ -1807,6 +1808,7 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
param.vendorExtensions.put("x-py-typing", typing);
} else {
param.vendorExtensions.put("x-py-typing", String.format(Locale.ROOT, "Annotated[%s, %s]", typing, fieldCustomization));
importAnnotated = true;
}
}
@@ -1838,6 +1840,12 @@ public abstract class AbstractPythonCodegen extends DefaultCodegen implements Co
List<Map<String, String>> newImports = new ArrayList<>();
if (importAnnotated) {
Map<String, String> item = new HashMap<>();
item.put("import", String.format(Locale.ROOT, String.format(Locale.ROOT, "from typing_extensions import Annotated")));
newImports.add(item);
}
// need datetime import
if (!datetimeImports.isEmpty()) {
Map<String, String> item = new HashMap<>();

View File

@@ -204,6 +204,20 @@ abstract public class AbstractRubyCodegen extends DefaultCodegen implements Code
return addRegularExpressionDelimiter(pattern);
}
@Override
public String addRegularExpressionDelimiter(String pattern) {
if (StringUtils.isEmpty(pattern)) {
return pattern;
}
if (!pattern.matches("^/.*")) {
// Perform a negative lookbehind on each `/` to ensure that it is escaped.
return "/" + pattern.replaceAll("(?<!\\\\)\\/", "\\\\/") + "/";
}
return pattern;
}
@Override
public String toParamName(String name) {
// obtain the name from parameterNameMapping directly if provided

View File

@@ -1135,21 +1135,21 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
}
@Override
public String toAnyOfName(List<String> names, ComposedSchema composedSchema) {
public String toAnyOfName(List<String> names, Schema composedSchema) {
List<String> types = getTypesFromSchemas(composedSchema.getAnyOf());
return String.join(" | ", types);
}
@Override
public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
public String toOneOfName(List<String> names, Schema composedSchema) {
List<String> types = getTypesFromSchemas(composedSchema.getOneOf());
return String.join(" | ", types);
}
@Override
public String toAllOfName(List<String> names, ComposedSchema composedSchema) {
public String toAllOfName(List<String> names, Schema composedSchema) {
List<String> types = getTypesFromSchemas(composedSchema.getAllOf());
return String.join(" & ", types);

View File

@@ -233,7 +233,7 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
"Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.");
disallowAdditionalPropertiesIfNotPresentOpt.setEnum(disallowAdditionalPropertiesIfNotPresentOpts);
cliOptions.add(disallowAdditionalPropertiesIfNotPresentOpt);
this.setDisallowAdditionalPropertiesIfNotPresent(true);
this.setDisallowAdditionalPropertiesIfNotPresent(false);
ImmutableMap.Builder<String, String> frameworkBuilder = new ImmutableMap.Builder<>();
for (FrameworkStrategy frameworkStrategy : frameworkStrategies) {
@@ -322,6 +322,10 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
CodegenConstants.EQUATABLE_DESC,
this.equatable);
addSwitch("useSourceGeneration",
"Use source generation where available (only `generichost` library supports this option).",
this.getUseSourceGeneration());
supportedLibraries.put(GENERICHOST, "HttpClient with Generic Host dependency injection (https://docs.microsoft.com/en-us/dotnet/core/extensions/generic-host) "
+ "(Experimental. Subject to breaking changes without notice.)");
supportedLibraries.put(HTTPCLIENT, "HttpClient (https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient) "
@@ -788,6 +792,7 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
syncBooleanProperty(additionalProperties, CodegenConstants.NON_PUBLIC_API, this::setNonPublicApi, isNonPublicApi());
syncBooleanProperty(additionalProperties, CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, this::setUseOneOfDiscriminatorLookup, this.useOneOfDiscriminatorLookup);
syncBooleanProperty(additionalProperties, "supportsFileParameters", this::setSupportsFileParameters, this.supportsFileParameters);
syncBooleanProperty(additionalProperties, "useSourceGeneration", this::setUseSourceGeneration, this.useSourceGeneration);
final String testPackageName = testPackageName();
String packageFolder = sourceFolder + File.separator + packageName;
@@ -855,6 +860,14 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
this.setTypeMapping();
}
@Override
public void setUseSourceGeneration(final Boolean useSourceGeneration) {
if (useSourceGeneration && !this.additionalProperties.containsKey(NET_70_OR_LATER)) {
throw new RuntimeException("Source generation is only compatible with .Net 7 or later.");
}
this.useSourceGeneration = useSourceGeneration;
}
public void setClientPackage(String clientPackage) {
this.clientPackage = clientPackage;
}
@@ -1618,7 +1631,7 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
* ModelUtils.isMapSchema
* In other generators, isMap is true for all type object schemas
*/
if (schema.getProperties() != null || schema.getRequired() != null && !(schema instanceof ComposedSchema)) {
if (schema.getProperties() != null || schema.getRequired() != null && !(ModelUtils.isComposedSchema(schema))) {
// passing null to allProperties and allRequired as there's no parent
addVars(m, unaliasPropertySchema(schema.getProperties()), schema.getRequired(), null, null);
}

View File

@@ -194,7 +194,7 @@ public class CSharpReducedClientCodegen extends AbstractCSharpCodegen {
"Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.");
disallowAdditionalPropertiesIfNotPresentOpt.setEnum(disallowAdditionalPropertiesIfNotPresentOpts);
cliOptions.add(disallowAdditionalPropertiesIfNotPresentOpt);
this.setDisallowAdditionalPropertiesIfNotPresent(true);
this.setDisallowAdditionalPropertiesIfNotPresent(false);
ImmutableMap.Builder<String, String> frameworkBuilder = new ImmutableMap.Builder<>();
for (FrameworkStrategy frameworkStrategy : frameworkStrategies) {
@@ -1142,7 +1142,7 @@ public class CSharpReducedClientCodegen extends AbstractCSharpCodegen {
* ModelUtils.isMapSchema
* In other generators, isMap is true for all type object schemas
*/
if (schema.getProperties() != null || schema.getRequired() != null && !(schema instanceof ComposedSchema)) {
if (schema.getProperties() != null || schema.getRequired() != null && !(ModelUtils.isComposedSchema(schema))) {
// passing null to allProperties and allRequired as there's no parent
addVars(m, unaliasPropertySchema(schema.getProperties()), schema.getRequired(), null, null);
}

View File

@@ -136,7 +136,7 @@ public class GoClientCodegen extends AbstractGoCodegen {
"Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.");
disallowAdditionalPropertiesIfNotPresentOpt.setEnum(disallowAdditionalPropertiesIfNotPresentOpts);
cliOptions.add(disallowAdditionalPropertiesIfNotPresentOpt);
this.setDisallowAdditionalPropertiesIfNotPresent(true);
this.setDisallowAdditionalPropertiesIfNotPresent(false);
}
/**
@@ -413,10 +413,7 @@ public class GoClientCodegen extends AbstractGoCodegen {
if (ModelUtils.isStringSchema(p) || isAllOfStringSchema(p)) {
Object defaultObj = p.getDefault();
if (defaultObj != null) {
if (defaultObj instanceof java.lang.String) {
return "\"" + escapeText((String) defaultObj) + "\"";
}
return "\"" + escapeText(defaultObj.toString()) + "\"";
return "\"" + escapeText(String.valueOf(defaultObj)) + "\"";
}
return null;
}

View File

@@ -1233,7 +1233,7 @@ public class JavascriptApolloClientCodegen extends DefaultCodegen implements Cod
public GeneratorLanguage generatorLanguage() { return GeneratorLanguage.JAVASCRIPT; }
@Override
protected void addImport(ComposedSchema composed, Schema childSchema, CodegenModel model, String modelName ) {
protected void addImport(Schema composed, Schema childSchema, CodegenModel model, String modelName ) {
// import everything (including child schema of a composed schema)
addImport(model, modelName);
}

View File

@@ -1242,7 +1242,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
}
@Override
protected void addImport(ComposedSchema composed, Schema childSchema, CodegenModel model, String modelName) {
protected void addImport(Schema composed, Schema childSchema, CodegenModel model, String modelName) {
// import everything (including child schema of a composed schema)
addImport(model, modelName);
}

View File

@@ -50,6 +50,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
private boolean useCoroutines = false;
private boolean useMutiny = false;
private boolean returnResponse = false;
private boolean omitGradleWrapper = false;
// This is here to potentially warn the user when an option is not supported by the target framework.
private Map<String, List<String>> optionsSupportedPerFramework = new ImmutableMap.Builder<String, List<String>>()
@@ -60,7 +61,8 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
Constants.CORS,
Constants.COMPRESSION,
Constants.RESOURCES,
Constants.METRICS
Constants.METRICS,
Constants.OMIT_GRADLE_WRAPPER
))
.put(Constants.JAXRS_SPEC, Arrays.asList(
USE_BEANVALIDATION,
@@ -132,6 +134,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
addSwitch(Constants.USE_COROUTINES, Constants.USE_COROUTINES_DESC, useCoroutines);
addSwitch(Constants.USE_MUTINY, Constants.USE_MUTINY_DESC, useMutiny);
addSwitch(Constants.RETURN_RESPONSE, Constants.RETURN_RESPONSE_DESC, returnResponse);
addSwitch(Constants.OMIT_GRADLE_WRAPPER, Constants.OMIT_GRADLE_WRAPPER_DESC, omitGradleWrapper);
addSwitch(USE_JAKARTA_EE, Constants.USE_JAKARTA_EE_DESC, useJakartaEe);
}
@@ -183,6 +186,14 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
return resourcesFeatureEnabled;
}
public boolean getOmitGradleWrapper() {
return omitGradleWrapper;
}
public void setOmitGradleWrapper(boolean omitGradleWrapper) {
this.omitGradleWrapper = omitGradleWrapper;
}
public void setResourcesFeatureEnabled(Boolean resourcesFeatureEnabled) {
this.resourcesFeatureEnabled = resourcesFeatureEnabled;
}
@@ -247,6 +258,10 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION));
}
if (additionalProperties.containsKey(Constants.OMIT_GRADLE_WRAPPER)) {
setOmitGradleWrapper(Boolean.parseBoolean(additionalProperties.get(Constants.OMIT_GRADLE_WRAPPER).toString()));
}
writePropertyBack(USE_BEANVALIDATION, useBeanValidation);
// set default library to "ktor"
@@ -360,6 +375,8 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen implements BeanVa
public static final String USE_JAKARTA_EE_DESC = "whether to use Jakarta EE namespace instead of javax";
public static final String USE_MUTINY = "useMutiny";
public static final String USE_MUTINY_DESC = "Whether to use Mutiny (should not be used with useCoroutines). This option is currently supported only when using jaxrs-spec library.";
public static final String OMIT_GRADLE_WRAPPER = "omitGradleWrapper";
public static final String OMIT_GRADLE_WRAPPER_DESC = "Whether to omit Gradle wrapper for creating a sub project.";
}
@Override

View File

@@ -239,6 +239,11 @@ public class LuaClientCodegen extends DefaultCodegen implements CodegenConfig {
@Override
public String toVarName(String name) {
// obtain the name from nameMapping directly if provided
if (nameMapping.containsKey(name)) {
return nameMapping.get(name);
}
// replace - with _ e.g. created-at => created_at
name = sanitizeName(name.replaceAll("-", "_"));
@@ -263,6 +268,11 @@ public class LuaClientCodegen extends DefaultCodegen implements CodegenConfig {
@Override
public String toParamName(String name) {
// obtain the name from parameterNameMapping directly if provided
if (parameterNameMapping.containsKey(name)) {
return parameterNameMapping.get(name);
}
return toVarName(name);
}
@@ -273,6 +283,11 @@ public class LuaClientCodegen extends DefaultCodegen implements CodegenConfig {
@Override
public String toModelFilename(String name) {
// obtain the name from modelNameMapping directly if provided
if (modelNameMapping.containsKey(name)) {
return modelNameMapping.get(name);
}
if (!StringUtils.isEmpty(modelNamePrefix)) {
name = modelNamePrefix + "_" + name;
}

View File

@@ -266,19 +266,19 @@ public class N4jsClientCodegen extends DefaultCodegen implements CodegenConfig {
}
@Override
public String toAnyOfName(List<String> names, ComposedSchema composedSchema) {
public String toAnyOfName(List<String> names, Schema composedSchema) {
List<String> types = getTypesFromSchemas(composedSchema.getAnyOf());
return String.join(" | ", types);
}
@Override
public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
public String toOneOfName(List<String> names, Schema composedSchema) {
List<String> types = getTypesFromSchemas(composedSchema.getOneOf());
return String.join(" | ", types);
}
@Override
public String toAllOfName(List<String> names, ComposedSchema composedSchema) {
public String toAllOfName(List<String> names, Schema composedSchema) {
List<String> types = getTypesFromSchemas(composedSchema.getAllOf());
return String.join(" & ", types);
}

View File

@@ -317,6 +317,11 @@ public class PerlClientCodegen extends DefaultCodegen implements CodegenConfig {
@Override
public String toVarName(String name) {
// obtain the name from nameMapping directly if provided
if (nameMapping.containsKey(name)) {
return nameMapping.get(name);
}
// return the name in underscore style
// PhoneNumber => phone_number
name = underscore(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
@@ -331,12 +336,22 @@ public class PerlClientCodegen extends DefaultCodegen implements CodegenConfig {
@Override
public String toParamName(String name) {
// obtain the name from parameterNameMapping directly if provided
if (parameterNameMapping.containsKey(name)) {
return parameterNameMapping.get(name);
}
// should be the same as variable name
return toVarName(name);
}
@Override
public String toModelName(String name) {
// obtain the name from modelNameMapping directly if provided
if (modelNameMapping.containsKey(name)) {
return modelNameMapping.get(name);
}
// We need to check if schema-mapping has a different model for this class, so we use it
// instead of the auto-generated one.
if (schemaMapping.containsKey(name)) {

View File

@@ -20,11 +20,14 @@ package org.openapitools.codegen.languages;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,6 +36,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
public class PhpNextgenClientCodegen extends AbstractPhpCodegen {
@SuppressWarnings("hiding")
@@ -122,4 +126,32 @@ public class PhpNextgenClientCodegen extends AbstractPhpCodegen {
supportingFiles.add(new SupportingFile(".phplint.mustache", "", ".phplint.yml"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
}
@Override
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
final Map<String, ModelsMap> processed = super.postProcessAllModels(objs);
for (Map.Entry<String, ModelsMap> entry : processed.entrySet()) {
entry.setValue(postProcessModelsMap(entry.getValue()));
}
return processed;
}
private ModelsMap postProcessModelsMap(ModelsMap objs) {
for (ModelMap m : objs.getModels()) {
CodegenModel model = m.getModel();
if (model.isEnum) {
for (Map<String, Object> enumVars : (List<Map<String, Object>>) model.getAllowableValues().get("enumVars")) {
if ((Boolean) enumVars.get("isString")) {
model.vendorExtensions.putIfAbsent("x-php-enum-type", "string");
} else {
model.vendorExtensions.putIfAbsent("x-php-enum-type", "int");
}
}
}
}
return objs;
}
}

View File

@@ -568,7 +568,7 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
"Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.");
disallowAdditionalPropertiesIfNotPresentOpt.setEnum(disallowAdditionalPropertiesIfNotPresentOpts);
cliOptions.add(disallowAdditionalPropertiesIfNotPresentOpt);
this.setDisallowAdditionalPropertiesIfNotPresent(true);
this.setDisallowAdditionalPropertiesIfNotPresent(false);
// default value in the template
additionalProperties.put("powershellVersion", "6.2"); // minimal PS version
@@ -910,6 +910,11 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
*/
@Override
public String toModelName(String name) {
// obtain the name from modelNameMapping directly if provided
if (modelNameMapping.containsKey(name)) {
return modelNameMapping.get(name);
}
// check if schema-mapping has a different model for this class, so we can use it
// instead of the auto-generated one.
if (schemaMapping.containsKey(name)) {
@@ -1016,6 +1021,11 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
@Override
public String toParamName(String name) {
// obtain the name from parameterNameMapping directly if provided
if (parameterNameMapping.containsKey(name)) {
return parameterNameMapping.get(name);
}
// sanitize and camelize parameter name
// pet_id => PetId
name = camelize(sanitizeName(name));
@@ -1148,6 +1158,11 @@ public class PowerShellClientCodegen extends DefaultCodegen implements CodegenCo
@Override
public String toVarName(String name) {
// obtain the name from nameMapping directly if provided
if (nameMapping.containsKey(name)) {
return nameMapping.get(name);
}
// sanitize name
name = sanitizeName(name);

View File

@@ -184,7 +184,7 @@ public class PythonClientCodegen extends AbstractPythonCodegen implements Codege
"Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.");
disallowAdditionalPropertiesIfNotPresentOpt.setEnum(disallowAdditionalPropertiesIfNotPresentOpts);
cliOptions.add(disallowAdditionalPropertiesIfNotPresentOpt);
this.setDisallowAdditionalPropertiesIfNotPresent(true);
this.setDisallowAdditionalPropertiesIfNotPresent(false);
}
@Override

View File

@@ -233,7 +233,7 @@ public class RClientCodegen extends DefaultCodegen implements CodegenConfig {
"Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.");
disallowAdditionalPropertiesIfNotPresentOpt.setEnum(disallowAdditionalPropertiesIfNotPresentOpts);
cliOptions.add(disallowAdditionalPropertiesIfNotPresentOpt);
this.setDisallowAdditionalPropertiesIfNotPresent(true);
this.setDisallowAdditionalPropertiesIfNotPresent(false);
}

View File

@@ -1245,7 +1245,7 @@ public class RustServerCodegen extends AbstractRustCodegen implements CodegenCon
}
@Override
public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
public String toOneOfName(List<String> names, Schema composedSchema) {
List<Schema> schemas = ModelUtils.getInterfaces(composedSchema);
List<String> types = new ArrayList<>();
@@ -1256,7 +1256,7 @@ public class RustServerCodegen extends AbstractRustCodegen implements CodegenCon
}
@Override
public String toAnyOfName(List<String> names, ComposedSchema composedSchema) {
public String toAnyOfName(List<String> names, Schema composedSchema) {
List<Schema> schemas = ModelUtils.getInterfaces(composedSchema);
List<String> types = new ArrayList<>();

View File

@@ -313,7 +313,7 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
}
@Override
protected void addImport(ComposedSchema composed, Schema childSchema, CodegenModel model, String modelName) {
protected void addImport(Schema composed, Schema childSchema, CodegenModel model, String modelName) {
// import everything (including child schema of a composed schema)
addImport(model, modelName);
}

View File

@@ -502,7 +502,7 @@ public class TypeScriptClientCodegen extends AbstractTypeScriptClientCodegen imp
@Override
protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
codegenModel.additionalPropertiesType = getTypeDeclaration((Schema) schema.getAdditionalProperties());
codegenModel.additionalPropertiesType = getSchemaType(ModelUtils.getAdditionalProperties(schema));
addImport(codegenModel, codegenModel.additionalPropertiesType);
}

View File

@@ -423,7 +423,7 @@ public class TypeScriptRxjsClientCodegen extends AbstractTypeScriptClientCodegen
}
@Override
protected void addImport(ComposedSchema composed, Schema childSchema, CodegenModel model, String modelName) {
protected void addImport(Schema composed, Schema childSchema, CodegenModel model, String modelName) {
// import everything (including child schema of a composed schema)
addImport(model, modelName);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
import static org.openapitools.codegen.utils.StringUtils.underscore;
/**
* Double quote the text if it's not already the case.
*
* Register:
* <pre>
* additionalProperties.put("doublequote", new DoubleQuoteLambda());
* </pre>
*
* Use:
* <pre>
* {{#doublequote}}{{summary}}{{/doublequote}}
* </pre>
*/
public class DoubleQuoteLambda implements Mustache.Lambda {
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String input = fragment.execute();
if (input.startsWith("\"") && input.endsWith("\"")) {
writer.write(input);
} else {
writer.write("\"" + input + "\"");
}
}
}

View File

@@ -34,7 +34,7 @@ import static org.openapitools.codegen.utils.StringUtils.underscore;
*
* Use:
* <pre>
* {{#fforwardslash}}{{summary}}{{/forwardslash}}
* {{#forwardslash}}{{summary}}{{/forwardslash}}
* </pre>
*/
public class ForwardSlashLambda implements Mustache.Lambda {

View File

@@ -38,15 +38,29 @@ import java.io.Writer;
*/
public class JoinWithCommaLambda implements Mustache.Lambda {
public JoinWithCommaLambda() {
private final String delimit;
private final String coalesce;
private final boolean trimInput;
public JoinWithCommaLambda() {
this.delimit = " ";
this.coalesce = ", ";
this.trimInput = true;
}
public JoinWithCommaLambda(boolean trimInput, String delimit, String coalesce) {
this.delimit = delimit;
this.coalesce = coalesce;
this.trimInput = trimInput;
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String[] substr = fragment.execute().trim().split(" ");
String[] input = this.trimInput
? fragment.execute().trim().split(delimit)
: fragment.execute().split(delimit);
writer.write(String.join(", ", substr));
writer.write(String.join(coalesce, input));
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.templating.mustache;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* Split text by the delimiter and then write only the unique entries
*
* Register:
* <pre>
* additionalProperties.put("unique", new UniqueLambda());
* </pre>
*
* Use:
* <pre>
* {{#unique}}{{name}}{{/unique}}
* </pre>
*/
public class UniqueLambda implements Mustache.Lambda {
private final String delimiter;
private final boolean withNewLine;
public UniqueLambda(String delimiter, boolean withNewLine)
{
this.delimiter = delimiter;
this.withNewLine = withNewLine;
}
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String[] parts = fragment.execute().split(this.delimiter);
List<String> uniqueLines = Arrays.stream(parts).distinct().collect(Collectors.toList());
writer.write(String.join(delimiter, uniqueLines));
if (withNewLine) {
writer.write("\n");
}
}
}

View File

@@ -331,20 +331,20 @@ public class ModelUtils {
}
}
}
if (schema instanceof ComposedSchema) {
List<Schema> oneOf = ((ComposedSchema) schema).getOneOf();
if (isComposedSchema(schema)) {
List<Schema> oneOf = schema.getOneOf();
if (oneOf != null) {
for (Schema s : oneOf) {
visitSchema(openAPI, s, mimeType, visitedSchemas, visitor);
}
}
List<Schema> allOf = ((ComposedSchema) schema).getAllOf();
List<Schema> allOf = schema.getAllOf();
if (allOf != null) {
for (Schema s : allOf) {
visitSchema(openAPI, s, mimeType, visitedSchemas, visitor);
}
}
List<Schema> anyOf = ((ComposedSchema) schema).getAnyOf();
List<Schema> anyOf = schema.getAnyOf();
if (anyOf != null) {
for (Schema s : anyOf) {
visitSchema(openAPI, s, mimeType, visitedSchemas, visitor);
@@ -367,7 +367,7 @@ public class ModelUtils {
Map<String, Schema> properties = schema.getProperties();
if (properties != null) {
for (Schema property : properties.values()) {
visitSchema(openAPI, property, mimeType, visitedSchemas, visitor);
visitSchema(openAPI, property, null, visitedSchemas, visitor);
}
}
}
@@ -453,7 +453,32 @@ public class ModelUtils {
* @return true if the specified schema is a Composed schema.
*/
public static boolean isComposedSchema(Schema schema) {
return schema instanceof ComposedSchema;
if (schema == null) {
return false;
}
// in 3.0, ComposeSchema is used for anyOf/oneOf/allOf
// in 3.1, it's not the case so we need more checks below
if (schema instanceof ComposedSchema) {
return true;
}
// has oneOf
if (schema.getOneOf() != null) {
return true;
}
// has anyOf
if (schema.getAnyOf() != null) {
return true;
}
// has allOf
if (schema.getAllOf() != null) {
return true;
}
return false;
}
/**
@@ -678,7 +703,8 @@ public class ModelUtils {
// has properties
((null != schema.getProperties() && !schema.getProperties().isEmpty())
// composed schema is a model, consider very simple ObjectSchema a model
|| (schema instanceof ComposedSchema || schema instanceof ObjectSchema));
|| isComposedSchema(schema)
|| schema instanceof ObjectSchema);
}
/**
@@ -752,9 +778,8 @@ public class ModelUtils {
}
// not free-form if allOf, anyOf, oneOf is not empty
if (schema instanceof ComposedSchema) {
ComposedSchema cs = (ComposedSchema) schema;
List<Schema> interfaces = ModelUtils.getInterfaces(cs);
if (isComposedSchema(schema)) {
List<Schema> interfaces = ModelUtils.getInterfaces(schema);
if (interfaces != null && !interfaces.isEmpty()) {
return false;
}
@@ -1053,8 +1078,8 @@ public class ModelUtils {
return true;
}
}
if (schema instanceof ComposedSchema) {
List<Schema> oneOf = ((ComposedSchema) schema).getOneOf();
if (isComposedSchema(schema)) {
List<Schema> oneOf = schema.getOneOf();
if (oneOf != null) {
for (Schema s : oneOf) {
if (hasSelfReference(openAPI, s, visitedSchemaNames)) {
@@ -1062,7 +1087,7 @@ public class ModelUtils {
}
}
}
List<Schema> allOf = ((ComposedSchema) schema).getAllOf();
List<Schema> allOf = schema.getAllOf();
if (allOf != null) {
for (Schema s : allOf) {
if (hasSelfReference(openAPI, s, visitedSchemaNames)) {
@@ -1070,7 +1095,7 @@ public class ModelUtils {
}
}
}
List<Schema> anyOf = ((ComposedSchema) schema).getAnyOf();
List<Schema> anyOf = schema.getAnyOf();
if (anyOf != null) {
for (Schema s : anyOf) {
if (hasSelfReference(openAPI, s, visitedSchemaNames)) {
@@ -1270,8 +1295,8 @@ public class ModelUtils {
Map<String, List<Entry<String, Schema>>> groupedByParent = allSchemas.entrySet().stream()
.filter(entry -> isComposedSchema(entry.getValue()))
.filter(entry -> getParentName((ComposedSchema) entry.getValue(), allSchemas) != null)
.collect(Collectors.groupingBy(entry -> getParentName((ComposedSchema) entry.getValue(), allSchemas)));
.filter(entry -> getParentName((Schema) entry.getValue(), allSchemas) != null)
.collect(Collectors.groupingBy(entry -> getParentName((Schema) entry.getValue(), allSchemas)));
return groupedByParent.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue().stream().map(e -> e.getKey()).collect(Collectors.toList())));
@@ -1283,7 +1308,7 @@ public class ModelUtils {
* @param composed schema (alias or direct reference)
* @return a list of schema defined in allOf, anyOf or oneOf
*/
public static List<Schema> getInterfaces(ComposedSchema composed) {
public static List<Schema> getInterfaces(Schema composed) {
if (composed.getAllOf() != null && !composed.getAllOf().isEmpty()) {
return composed.getAllOf();
} else if (composed.getAnyOf() != null && !composed.getAnyOf().isEmpty()) {
@@ -1324,7 +1349,7 @@ public class ModelUtils {
* @param allSchemas all schemas
* @return the name of the parent model
*/
public static String getParentName(ComposedSchema composedSchema, Map<String, Schema> allSchemas) {
public static String getParentName(Schema composedSchema, Map<String, Schema> allSchemas) {
List<Schema> interfaces = getInterfaces(composedSchema);
int nullSchemaChildrenCount = 0;
boolean hasAmbiguousParents = false;
@@ -1376,7 +1401,7 @@ public class ModelUtils {
* @param includeAncestors if true, include the indirect ancestors in the return value. If false, return the direct parents.
* @return the name of the parent model
*/
public static List<String> getAllParentsName(ComposedSchema composedSchema, Map<String, Schema> allSchemas, boolean includeAncestors) {
public static List<String> getAllParentsName(Schema composedSchema, Map<String, Schema> allSchemas, boolean includeAncestors) {
List<Schema> interfaces = getInterfaces(composedSchema);
List<String> names = new ArrayList<String>();
@@ -1392,8 +1417,8 @@ public class ModelUtils {
} else if (hasOrInheritsDiscriminator(s, allSchemas, new ArrayList<Schema>())) {
// discriminator.propertyName is used or x-parent is used
names.add(parentName);
if (includeAncestors && s instanceof ComposedSchema) {
names.addAll(getAllParentsName((ComposedSchema) s, allSchemas, true));
if (includeAncestors && isComposedSchema(s)) {
names.addAll(getAllParentsName(s, allSchemas, true));
}
} else {
// not a parent since discriminator.propertyName is not set
@@ -1433,9 +1458,8 @@ public class ModelUtils {
} else {
LOGGER.error("Failed to obtain schema from {}", parentName);
}
} else if (schema instanceof ComposedSchema) {
final ComposedSchema composed = (ComposedSchema) schema;
final List<Schema> interfaces = getInterfaces(composed);
} else if (isComposedSchema(schema)) {
final List<Schema> interfaces = getInterfaces(schema);
for (Schema i : interfaces) {
if (hasOrInheritsDiscriminator(i, allSchemas, visitedSchemas)) {
return true;
@@ -1502,8 +1526,8 @@ public class ModelUtils {
return Boolean.parseBoolean(schema.getExtensions().get("x-nullable").toString());
}
// In OAS 3.1, the recommended way to define a nullable property or object is to use oneOf.
if (schema instanceof ComposedSchema) {
return isNullableComposedSchema(((ComposedSchema) schema));
if (isComposedSchema(schema)) {
return isNullableComposedSchema(schema);
}
return false;
}
@@ -1524,7 +1548,7 @@ public class ModelUtils {
* @param schema the OAS composed schema.
* @return true if the composed schema is nullable.
*/
public static boolean isNullableComposedSchema(ComposedSchema schema) {
public static boolean isNullableComposedSchema(Schema schema) {
List<Schema> oneOf = schema.getOneOf();
if (oneOf != null && oneOf.size() <= 2) {
for (Schema s : oneOf) {

View File

@@ -69,13 +69,12 @@ class OpenApiSchemaValidations extends GenericValidator<SchemaWrapper> {
Schema schema = schemaWrapper.getSchema();
ValidationRule.Result result = ValidationRule.Pass.empty();
if (schema instanceof ComposedSchema) {
final ComposedSchema composed = (ComposedSchema) schema;
if (ModelUtils.isComposedSchema(schema)) {
// check for loosely defined oneOf extension requirements.
// This is a recommendation because the 3.0.x spec is not clear enough on usage of oneOf.
// see https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.section.9.2.1.3 and the OAS section on 'Composition and Inheritance'.
if (composed.getOneOf() != null && composed.getOneOf().size() > 0) {
if (composed.getProperties() != null && composed.getProperties().size() >= 1 && composed.getProperties().get("discriminator") == null) {
if (schema.getOneOf() != null && schema.getOneOf().size() > 0) {
if (schema.getProperties() != null && schema.getProperties().size() >= 1 && schema.getProperties().get("discriminator") == null) {
// not necessarily "invalid" here, but we trigger the recommendation which requires the method to return false.
result = ValidationRule.Fail.empty();
}
@@ -91,7 +90,7 @@ class OpenApiSchemaValidations extends GenericValidator<SchemaWrapper> {
* Note: the validator invokes checkNullType() for every top-level schema in the OAS document. The method
* is not called for nested schemas that are defined inline.
*
* @param schema An input schema, regardless of the type of schema.
* @param schemaWrapper An input schema, regardless of the type of schema.
* @return {@link ValidationRule.Pass} if the check succeeds, otherwise {@link ValidationRule.Fail}
*/
private static ValidationRule.Result checkNullType(SchemaWrapper schemaWrapper) {

View File

@@ -0,0 +1,45 @@
{{#additionalPropertiesType}}
/**
* A container for additional, undeclared properties.
* This is a holder for any undeclared properties as specified with
* the 'additionalProperties' keyword in the OAS document.
*/
private Map<String, {{{.}}}> additionalProperties;
/**
* Set the additional (undeclared) property with the specified name and value.
* If the property does not already exist, create it otherwise replace it.
* @param key the name of the property
* @param value the value of the property
* @return self reference
*/
@JsonAnySetter
public {{classname}} putAdditionalProperty(String key, {{{.}}} value) {
if (this.additionalProperties == null) {
this.additionalProperties = new HashMap<String, {{{.}}}>();
}
this.additionalProperties.put(key, value);
return this;
}
/**
* Return the additional (undeclared) properties.
* @return the additional (undeclared) properties
*/
@JsonAnyGetter
public Map<String, {{{.}}}> getAdditionalProperties() {
return additionalProperties;
}
/**
* Return the additional (undeclared) property with the specified name.
* @param key the name of the property
* @return the additional (undeclared) property with the specified name
*/
public {{{.}}} getAdditionalProperty(String key) {
if (this.additionalProperties == null) {
return null;
}
return this.additionalProperties.get(key);
}
{{/additionalPropertiesType}}

View File

@@ -101,14 +101,14 @@ test {
}
ext {
swagger_annotations_version = "1.5.24"
jackson_version = "2.13.4"
jackson_databind_version = "2.13.4.2"
swagger_annotations_version = "1.6.11"
jackson_version = "2.14.3"
jackson_databind_version = "2.14.3"
{{#openApiNullable}}
jackson_databind_nullable_version = "0.2.6"
{{/openApiNullable}}
jakarta_annotation_version = "1.3.5"
feign_version = "10.11"
feign_version = "10.12"
feign_form_version = "3.8.0"
junit_version = "5.7.0"
scribejava_version = "8.0.0"
@@ -139,7 +139,7 @@ dependencies {
testImplementation "org.junit.jupiter:junit-jupiter:$junit_version"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_version"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junit_version"
testImplementation "com.github.tomakehurst:wiremock-jre8:2.27.2"
testImplementation "com.github.tomakehurst:wiremock-jre8:2.35.1"
testImplementation "org.hamcrest:hamcrest:2.2"
testImplementation "commons-io:commons-io:2.8.0"
testImplementation "ch.qos.logback:logback-classic:1.2.3"

View File

@@ -9,16 +9,16 @@ lazy val root = (project in file(".")).
publishArtifact in (Compile, packageDoc) := false,
resolvers += Resolver.mavenLocal,
libraryDependencies ++= Seq(
"io.swagger" % "swagger-annotations" % "1.5.24" % "compile",
"io.swagger" % "swagger-annotations" % "1.6.11" % "compile",
"com.google.code.findbugs" % "jsr305" % "3.0.2" % "compile",
"io.github.openfeign" % "feign-core" % "10.11" % "compile",
"io.github.openfeign" % "feign-jackson" % "10.11" % "compile",
"io.github.openfeign" % "feign-slf4j" % "10.11" % "compile",
"io.github.openfeign" % "feign-core" % "10.12" % "compile",
"io.github.openfeign" % "feign-jackson" % "10.12" % "compile",
"io.github.openfeign" % "feign-slf4j" % "10.12" % "compile",
"io.github.openfeign.form" % "feign-form" % "3.8.0" % "compile",
"io.github.openfeign" % "feign-okhttp" % "10.11" % "compile",
"com.fasterxml.jackson.core" % "jackson-core" % "2.13.4" % "compile",
"com.fasterxml.jackson.core" % "jackson-annotations" % "2.13.4" % "compile",
"com.fasterxml.jackson.core" % "jackson-databind" % "2.13.4.2" % "compile",
"io.github.openfeign" % "feign-okhttp" % "10.12" % "compile",
"com.fasterxml.jackson.core" % "jackson-core" % "2.14.3" % "compile",
"com.fasterxml.jackson.core" % "jackson-annotations" % "2.14.3" % "compile",
"com.fasterxml.jackson.core" % "jackson-databind" % "2.14.3" % "compile",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.9.10" % "compile",
"com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile",
"com.github.scribejava" % "scribejava-core" % "8.0.0" % "compile",
@@ -26,7 +26,7 @@ lazy val root = (project in file(".")).
"jakarta.annotation" % "jakarta.annotation-api" % "1.3.5" % "compile",
"org.junit.jupiter" % "junit-jupiter" % "5.7.0" % "test",
"org.junit.jupiter" % "junit-jupiter-params" % "5.7.0" % "test",
"com.github.tomakehurst" % "wiremock-jre8" % "2.27.2" % "test",
"com.github.tomakehurst" % "wiremock-jre8" % "2.35.1" % "test",
"org.hamcrest" % "hamcrest" % "2.2" % "test",
"commons-io" % "commons-io" % "2.8.0" % "test",
"com.novocode" % "junit-interface" % "0.10" % "test"

View File

@@ -0,0 +1,78 @@
{{>licenseInfo}}
package {{package}};
{{#useReflectionEqualsHashCode}}
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
{{/useReflectionEqualsHashCode}}
{{#models}}
{{#model}}
{{#additionalPropertiesType}}
import java.util.Map;
import java.util.HashMap;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
{{/additionalPropertiesType}}
{{/model}}
{{/models}}
import java.util.Objects;
import java.util.Arrays;
{{#imports}}
import {{import}};
{{/imports}}
{{#serializableModel}}
import java.io.Serializable;
{{/serializableModel}}
{{#jackson}}
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonTypeName;
{{#withXml}}
import com.fasterxml.jackson.dataformat.xml.annotation.*;
{{/withXml}}
{{#vendorExtensions.x-has-readonly-properties}}
import com.fasterxml.jackson.annotation.JsonCreator;
{{/vendorExtensions.x-has-readonly-properties}}
{{/jackson}}
{{#withXml}}
import {{javaxPackage}}.xml.bind.annotation.*;
import {{javaxPackage}}.xml.bind.annotation.adapters.*;
import io.github.threetenjaxb.core.*;
{{/withXml}}
{{#jsonb}}
import java.lang.reflect.Type;
import {{javaxPackage}}.json.bind.annotation.JsonbTypeDeserializer;
import {{javaxPackage}}.json.bind.annotation.JsonbTypeSerializer;
import {{javaxPackage}}.json.bind.serializer.DeserializationContext;
import {{javaxPackage}}.json.bind.serializer.JsonbDeserializer;
import {{javaxPackage}}.json.bind.serializer.JsonbSerializer;
import {{javaxPackage}}.json.bind.serializer.SerializationContext;
import {{javaxPackage}}.json.stream.JsonGenerator;
import {{javaxPackage}}.json.stream.JsonParser;
import {{javaxPackage}}.json.bind.annotation.JsonbProperty;
{{#vendorExtensions.x-has-readonly-properties}}
import {{javaxPackage}}.json.bind.annotation.JsonbCreator;
{{/vendorExtensions.x-has-readonly-properties}}
{{/jsonb}}
{{#parcelableModel}}
import android.os.Parcelable;
import android.os.Parcel;
{{/parcelableModel}}
{{#useBeanValidation}}
import {{javaxPackage}}.validation.constraints.*;
import {{javaxPackage}}.validation.Valid;
{{/useBeanValidation}}
{{#performBeanValidation}}
import org.hibernate.validator.constraints.*;
{{/performBeanValidation}}
{{#supportUrlQuery}}
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.StringJoiner;
{{/supportUrlQuery}}
{{#models}}
{{#model}}
{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}}{{/isEnum}}
{{/model}}
{{/models}}

View File

@@ -0,0 +1,593 @@
/**
* {{description}}{{^description}}{{classname}}{{/description}}{{#isDeprecated}}
* @deprecated{{/isDeprecated}}
*/{{#isDeprecated}}
@Deprecated{{/isDeprecated}}
{{#swagger1AnnotationLibrary}}
{{#description}}
@ApiModel(description = "{{{.}}}")
{{/description}}
{{/swagger1AnnotationLibrary}}
{{#jackson}}
@JsonPropertyOrder({
{{#vars}}
{{classname}}.JSON_PROPERTY_{{nameInSnakeCase}}{{^-last}},{{/-last}}
{{/vars}}
})
{{#isClassnameSanitized}}
{{^hasDiscriminatorWithNonEmptyMapping}}
@JsonTypeName("{{name}}")
{{/hasDiscriminatorWithNonEmptyMapping}}
{{/isClassnameSanitized}}
{{/jackson}}
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}
public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{#-last}} {{/-last}}{{/vendorExtensions.x-implements}}{
{{#serializableModel}}
private static final long serialVersionUID = 1L;
{{/serializableModel}}
{{#vars}}
{{#isEnum}}
{{^isContainer}}
{{>modelInnerEnum}}
{{/isContainer}}
{{#isContainer}}
{{#mostInnerItems}}
{{>modelInnerEnum}}
{{/mostInnerItems}}
{{/isContainer}}
{{/isEnum}}
{{#gson}}
public static final String SERIALIZED_NAME_{{nameInSnakeCase}} = "{{baseName}}";
{{/gson}}
{{#jackson}}
public static final String JSON_PROPERTY_{{nameInSnakeCase}} = "{{baseName}}";
{{/jackson}}
{{#withXml}}
{{#isXmlAttribute}}
@XmlAttribute(name = "{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}")
{{/isXmlAttribute}}
{{^isXmlAttribute}}
{{^isContainer}}
@XmlElement({{#xmlNamespace}}namespace="{{.}}", {{/xmlNamespace}}name = "{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}")
{{/isContainer}}
{{#isContainer}}
// Is a container wrapped={{isXmlWrapped}}
{{#items}}
// items.name={{name}} items.baseName={{baseName}} items.xmlName={{xmlName}} items.xmlNamespace={{xmlNamespace}}
// items.example={{example}} items.type={{dataType}}
@XmlElement({{#xmlNamespace}}namespace="{{.}}", {{/xmlNamespace}}name = "{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}")
{{/items}}
{{#isXmlWrapped}}
@XmlElementWrapper({{#xmlNamespace}}namespace="{{.}}", {{/xmlNamespace}}name = "{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}")
{{/isXmlWrapped}}
{{/isContainer}}
{{#isDateTime}}
@XmlJavaTypeAdapter(OffsetDateTimeXmlAdapter.class)
{{/isDateTime}}
{{/isXmlAttribute}}
{{/withXml}}
{{#gson}}
@SerializedName(SERIALIZED_NAME_{{nameInSnakeCase}})
{{/gson}}
{{#vendorExtensions.x-field-extra-annotation}}
{{{vendorExtensions.x-field-extra-annotation}}}
{{/vendorExtensions.x-field-extra-annotation}}
{{#vendorExtensions.x-is-jackson-optional-nullable}}
{{#isContainer}}
private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>undefined();
{{/isContainer}}
{{^isContainer}}
private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}};
{{/isContainer}}
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}
{{#isContainer}}
private {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
{{/isContainer}}
{{^isContainer}}
{{#isDiscriminator}}protected{{/isDiscriminator}}{{^isDiscriminator}}private{{/isDiscriminator}} {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
{{/isContainer}}
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{/vars}}
public {{classname}}() {
{{#parent}}
{{#parcelableModel}}
super();{{/parcelableModel}}
{{/parent}}
{{#gson}}
{{#discriminator}}
{{#discriminator.isEnum}}
this.{{{discriminatorName}}} = this.getClass().getSimpleName();
{{/discriminator.isEnum}}
{{/discriminator}}
{{/gson}}
}
{{#vendorExtensions.x-has-readonly-properties}}
{{^withXml}}
{{#jsonb}}@JsonbCreator{{/jsonb}}{{#jackson}}@JsonCreator{{/jackson}}
public {{classname}}(
{{#readOnlyVars}}
{{#jsonb}}@JsonbProperty(value = "{{baseName}}"{{^required}}, nullable = true{{/required}}){{/jsonb}}{{#jackson}}@JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}}){{/jackson}} {{{datatypeWithEnum}}} {{name}}{{^-last}}, {{/-last}}
{{/readOnlyVars}}
) {
this();
{{#readOnlyVars}}
this.{{name}} = {{#vendorExtensions.x-is-jackson-optional-nullable}}{{name}} == null ? JsonNullable.<{{{datatypeWithEnum}}}>undefined() : JsonNullable.of({{name}}){{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{name}}{{/vendorExtensions.x-is-jackson-optional-nullable}};
{{/readOnlyVars}}
}
{{/withXml}}
{{/vendorExtensions.x-has-readonly-properties}}
{{#vars}}
{{^isReadOnly}}
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
{{#vendorExtensions.x-is-jackson-optional-nullable}}this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}this.{{name}} = {{name}};{{/vendorExtensions.x-is-jackson-optional-nullable}}
return this;
}
{{#isArray}}
public {{classname}} add{{nameInCamelCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
{{#vendorExtensions.x-is-jackson-optional-nullable}}
if (this.{{name}} == null || !this.{{name}}.isPresent()) {
this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}});
}
try {
this.{{name}}.get().add({{name}}Item);
} catch (java.util.NoSuchElementException e) {
// this can never happen, as we make sure above that the value is present
}
return this;
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}
if (this.{{name}} == null) {
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}};
}
this.{{name}}.add({{name}}Item);
return this;
{{/vendorExtensions.x-is-jackson-optional-nullable}}
}
{{/isArray}}
{{#isMap}}
public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
{{#vendorExtensions.x-is-jackson-optional-nullable}}
if (this.{{name}} == null || !this.{{name}}.isPresent()) {
this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}});
}
try {
this.{{name}}.get().put(key, {{name}}Item);
} catch (java.util.NoSuchElementException e) {
// this can never happen, as we make sure above that the value is present
}
return this;
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}
{{^required}}
if (this.{{name}} == null) {
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}};
}
{{/required}}
this.{{name}}.put(key, {{name}}Item);
return this;
{{/vendorExtensions.x-is-jackson-optional-nullable}}
}
{{/isMap}}
{{/isReadOnly}}
/**
{{#description}}
* {{.}}
{{/description}}
{{^description}}
* Get {{name}}
{{/description}}
{{#minimum}}
* minimum: {{.}}
{{/minimum}}
{{#maximum}}
* maximum: {{.}}
{{/maximum}}
* @return {{name}}
{{#deprecated}}
* @deprecated
{{/deprecated}}
**/
{{#deprecated}}
@Deprecated
{{/deprecated}}
{{#required}}
{{#isNullable}}
@{{javaxPackage}}.annotation.Nullable
{{/isNullable}}
{{^isNullable}}
@{{javaxPackage}}.annotation.Nonnull
{{/isNullable}}
{{/required}}
{{^required}}
@{{javaxPackage}}.annotation.Nullable
{{/required}}
{{#jsonb}}
@JsonbProperty("{{baseName}}")
{{/jsonb}}
{{#useBeanValidation}}
{{>beanValidation}}
{{/useBeanValidation}}
{{#swagger1AnnotationLibrary}}
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}")
{{/swagger1AnnotationLibrary}}
{{#vendorExtensions.x-extra-annotation}}
{{{vendorExtensions.x-extra-annotation}}}
{{/vendorExtensions.x-extra-annotation}}
{{#vendorExtensions.x-is-jackson-optional-nullable}}
{{!unannotated, Jackson would pick this up automatically and add it *in addition* to the _JsonNullable getter field}}
@JsonIgnore
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}{{#jackson}}{{> jackson_annotations}}{{/jackson}}{{/vendorExtensions.x-is-jackson-optional-nullable}}
public {{{datatypeWithEnum}}} {{getter}}() {
{{#vendorExtensions.x-is-jackson-optional-nullable}}
{{#isReadOnly}}{{! A readonly attribute doesn't have setter => jackson will set null directly if explicitly returned by API, so make sure we have an empty JsonNullable}}
if ({{name}} == null) {
{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}};
}
{{/isReadOnly}}
return {{name}}.orElse(null);
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}
return {{name}};
{{/vendorExtensions.x-is-jackson-optional-nullable}}
}
{{#vendorExtensions.x-is-jackson-optional-nullable}}
{{> jackson_annotations}}
public JsonNullable<{{{datatypeWithEnum}}}> {{getter}}_JsonNullable() {
return {{name}};
}
{{/vendorExtensions.x-is-jackson-optional-nullable}}{{#vendorExtensions.x-is-jackson-optional-nullable}}
@JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}})
{{#isReadOnly}}private{{/isReadOnly}}{{^isReadOnly}}public{{/isReadOnly}} void {{setter}}_JsonNullable(JsonNullable<{{{datatypeWithEnum}}}> {{name}}) {
{{! For getters/setters that have name differing from attribute name, we must include setter (albeit private) for jackson to be able to set the attribute}}
this.{{name}} = {{name}};
}
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^isReadOnly}}
{{#vendorExtensions.x-setter-extra-annotation}} {{{vendorExtensions.x-setter-extra-annotation}}}
{{/vendorExtensions.x-setter-extra-annotation}}{{#jackson}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{> jackson_annotations}}{{/vendorExtensions.x-is-jackson-optional-nullable}}{{/jackson}} public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
{{#vendorExtensions.x-is-jackson-optional-nullable}}
this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}
this.{{name}} = {{name}};
{{/vendorExtensions.x-is-jackson-optional-nullable}}
}
{{/isReadOnly}}
{{/vars}}
{{>libraries/feign/additional_properties}}
@Override
public boolean equals(Object o) {
{{#useReflectionEqualsHashCode}}
return EqualsBuilder.reflectionEquals(this, o, false, null, true);
{{/useReflectionEqualsHashCode}}
{{^useReflectionEqualsHashCode}}
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}{{#hasVars}}
{{classname}} {{classVarName}} = ({{classname}}) o;
return {{#vars}}{{#vendorExtensions.x-is-jackson-optional-nullable}}equalsNullable(this.{{name}}, {{classVarName}}.{{name}}){{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{/vendorExtensions.x-is-jackson-optional-nullable}}{{^-last}} &&
{{/-last}}{{/vars}}{{#parent}} &&
super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}}
return {{#parent}}super.equals(o){{/parent}}{{^parent}}true{{/parent}};{{/hasVars}}
{{/useReflectionEqualsHashCode}}
}{{#vendorExtensions.x-jackson-optional-nullable-helpers}}
private static <T> boolean equalsNullable(JsonNullable<T> a, JsonNullable<T> b) {
return a == b || (a != null && b != null && a.isPresent() && b.isPresent() && Objects.deepEquals(a.get(), b.get()));
}{{/vendorExtensions.x-jackson-optional-nullable-helpers}}
@Override
public int hashCode() {
{{#useReflectionEqualsHashCode}}
return HashCodeBuilder.reflectionHashCode(this);
{{/useReflectionEqualsHashCode}}
{{^useReflectionEqualsHashCode}}
return Objects.hash({{#vars}}{{#vendorExtensions.x-is-jackson-optional-nullable}}hashCodeNullable({{name}}){{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{/vendorExtensions.x-is-jackson-optional-nullable}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}});
{{/useReflectionEqualsHashCode}}
}{{#vendorExtensions.x-jackson-optional-nullable-helpers}}
private static <T> int hashCodeNullable(JsonNullable<T> a) {
if (a == null) {
return 1;
}
return a.isPresent() ? Arrays.deepHashCode(new Object[]{a.get()}) : 31;
}{{/vendorExtensions.x-jackson-optional-nullable-helpers}}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class {{classname}} {\n");
{{#parent}}
sb.append(" ").append(toIndentedString(super.toString())).append("\n");
{{/parent}}
{{#vars}}
sb.append(" {{name}}: ").append(toIndentedString({{name}})).append("\n");
{{/vars}}
sb.append("}");
return sb.toString();
}
/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private{{#jsonb}} static{{/jsonb}} String toIndentedString(Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
{{#supportUrlQuery}}
/**
* Convert the instance into URL query string.
*
* @return URL query string
*/
public String toUrlQueryString() {
return toUrlQueryString(null);
}
/**
* Convert the instance into URL query string.
*
* @param prefix prefix of the query string
* @return URL query string
*/
public String toUrlQueryString(String prefix) {
String suffix = "";
String containerSuffix = "";
String containerPrefix = "";
if (prefix == null) {
// style=form, explode=true, e.g. /pet?name=cat&type=manx
prefix = "";
} else {
// deepObject style e.g. /pet?id[name]=cat&id[type]=manx
prefix = prefix + "[";
suffix = "]";
containerSuffix = "]";
containerPrefix = "[";
}
StringJoiner joiner = new StringJoiner("&");
{{#allVars}}
// add `{{baseName}}` to the URL query string
{{#isArray}}
{{#items.isPrimitiveType}}
{{#uniqueItems}}
if ({{getter}}() != null) {
int i = 0;
for ({{items.dataType}} _item : {{getter}}()) {
try {
joiner.add(String.format("%s{{baseName}}%s%s=%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, i, containerSuffix),
URLEncoder.encode(String.valueOf(_item), "UTF-8").replaceAll("\\+", "%20")));
} catch (UnsupportedEncodingException e) {
// Should never happen, UTF-8 is always supported
throw new RuntimeException(e);
}
}
i++;
}
{{/uniqueItems}}
{{^uniqueItems}}
if ({{getter}}() != null) {
for (int i = 0; i < {{getter}}().size(); i++) {
try {
joiner.add(String.format("%s{{baseName}}%s%s=%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, i, containerSuffix),
URLEncoder.encode(String.valueOf({{getter}}().get(i)), "UTF-8").replaceAll("\\+", "%20")));
} catch (UnsupportedEncodingException e) {
// Should never happen, UTF-8 is always supported
throw new RuntimeException(e);
}
}
}
{{/uniqueItems}}
{{/items.isPrimitiveType}}
{{^items.isPrimitiveType}}
{{#items.isModel}}
{{#uniqueItems}}
if ({{getter}}() != null) {
int i = 0;
for ({{items.dataType}} _item : {{getter}}()) {
if (_item != null) {
joiner.add(_item.toUrlQueryString(String.format("%s{{baseName}}%s%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, i, containerSuffix))));
}
}
i++;
}
{{/uniqueItems}}
{{^uniqueItems}}
if ({{getter}}() != null) {
for (int i = 0; i < {{getter}}().size(); i++) {
if ({{getter}}().get(i) != null) {
joiner.add({{getter}}().get(i).toUrlQueryString(String.format("%s{{baseName}}%s%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, i, containerSuffix))));
}
}
}
{{/uniqueItems}}
{{/items.isModel}}
{{^items.isModel}}
{{#uniqueItems}}
if ({{getter}}() != null) {
int i = 0;
for ({{items.dataType}} _item : {{getter}}()) {
if (_item != null) {
try {
joiner.add(String.format("%s{{baseName}}%s%s=%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, i, containerSuffix),
URLEncoder.encode(String.valueOf(_item), "UTF-8").replaceAll("\\+", "%20")));
} catch (UnsupportedEncodingException e) {
// Should never happen, UTF-8 is always supported
throw new RuntimeException(e);
}
}
i++;
}
}
{{/uniqueItems}}
{{^uniqueItems}}
if ({{getter}}() != null) {
for (int i = 0; i < {{getter}}().size(); i++) {
if ({{getter}}().get(i) != null) {
try {
joiner.add(String.format("%s{{baseName}}%s%s=%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, i, containerSuffix),
URLEncoder.encode(String.valueOf({{getter}}().get(i)), "UTF-8").replaceAll("\\+", "%20")));
} catch (UnsupportedEncodingException e) {
// Should never happen, UTF-8 is always supported
throw new RuntimeException(e);
}
}
}
}
{{/uniqueItems}}
{{/items.isModel}}
{{/items.isPrimitiveType}}
{{/isArray}}
{{^isArray}}
{{#isMap}}
{{#items.isPrimitiveType}}
if ({{getter}}() != null) {
for (String _key : {{getter}}().keySet()) {
try {
joiner.add(String.format("%s{{baseName}}%s%s=%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, _key, containerSuffix),
{{getter}}().get(_key), URLEncoder.encode(String.valueOf({{getter}}().get(_key)), "UTF-8").replaceAll("\\+", "%20")));
} catch (UnsupportedEncodingException e) {
// Should never happen, UTF-8 is always supported
throw new RuntimeException(e);
}
}
}
{{/items.isPrimitiveType}}
{{^items.isPrimitiveType}}
if ({{getter}}() != null) {
for (String _key : {{getter}}().keySet()) {
if ({{getter}}().get(_key) != null) {
joiner.add({{getter}}().get(_key).toUrlQueryString(String.format("%s{{baseName}}%s%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, _key, containerSuffix))));
}
}
}
{{/items.isPrimitiveType}}
{{/isMap}}
{{^isMap}}
{{#isPrimitiveType}}
if ({{getter}}() != null) {
try {
joiner.add(String.format("%s{{{baseName}}}%s=%s", prefix, suffix, URLEncoder.encode(String.valueOf({{{getter}}}()), "UTF-8").replaceAll("\\+", "%20")));
} catch (UnsupportedEncodingException e) {
// Should never happen, UTF-8 is always supported
throw new RuntimeException(e);
}
}
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isModel}}
if ({{getter}}() != null) {
joiner.add({{getter}}().toUrlQueryString(prefix + "{{{baseName}}}" + suffix));
}
{{/isModel}}
{{^isModel}}
if ({{getter}}() != null) {
try {
joiner.add(String.format("%s{{{baseName}}}%s=%s", prefix, suffix, URLEncoder.encode(String.valueOf({{{getter}}}()), "UTF-8").replaceAll("\\+", "%20")));
} catch (UnsupportedEncodingException e) {
// Should never happen, UTF-8 is always supported
throw new RuntimeException(e);
}
}
{{/isModel}}
{{/isPrimitiveType}}
{{/isMap}}
{{/isArray}}
{{/allVars}}
return joiner.toString();
}
{{/supportUrlQuery}}
{{#parcelableModel}}
public void writeToParcel(Parcel out, int flags) {
{{#model}}
{{#isArray}}
out.writeList(this);
{{/isArray}}
{{^isArray}}
{{#parent}}
super.writeToParcel(out, flags);
{{/parent}}
{{#vars}}
out.writeValue({{name}});
{{/vars}}
{{/isArray}}
{{/model}}
}
{{classname}}(Parcel in) {
{{#isArray}}
in.readTypedList(this, {{arrayModelType}}.CREATOR);
{{/isArray}}
{{^isArray}}
{{#parent}}
super(in);
{{/parent}}
{{#vars}}
{{#isPrimitiveType}}
{{name}} = ({{{datatypeWithEnum}}})in.readValue(null);
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{name}} = ({{{datatypeWithEnum}}})in.readValue({{complexType}}.class.getClassLoader());
{{/isPrimitiveType}}
{{/vars}}
{{/isArray}}
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<{{classname}}> CREATOR = new Parcelable.Creator<{{classname}}>() {
public {{classname}} createFromParcel(Parcel in) {
{{#model}}
{{#isArray}}
{{classname}} result = new {{classname}}();
result.addAll(in.readArrayList({{arrayModelType}}.class.getClassLoader()));
return result;
{{/isArray}}
{{^isArray}}
return new {{classname}}(in);
{{/isArray}}
{{/model}}
}
public {{classname}}[] newArray(int size) {
return new {{classname}}[size];
}
};
{{/parcelableModel}}
}

View File

@@ -365,7 +365,7 @@
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.27.2</version>
<version>2.35.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -381,15 +381,15 @@
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
{{#swagger1AnnotationLibrary}}
<swagger-annotations-version>1.6.6</swagger-annotations-version>
<swagger-annotations-version>1.6.11</swagger-annotations-version>
{{/swagger1AnnotationLibrary}}
{{#swagger2AnnotationLibrary}}
<swagger-annotations-version>2.2.9</swagger-annotations-version>
<swagger-annotations-version>2.2.15</swagger-annotations-version>
{{/swagger2AnnotationLibrary}}
<feign-version>10.11</feign-version>
<feign-version>10.12</feign-version>
<feign-form-version>3.8.0</feign-form-version>
{{#jackson}}
<jackson-version>2.13.4</jackson-version>
<jackson-version>2.14.3</jackson-version>
{{/jackson}}
{{#gson}}
<gson-version>2.8.6</gson-version>
@@ -397,7 +397,7 @@
{{#openApiNullable}}
<jackson-databind-nullable-version>0.2.6</jackson-databind-nullable-version>
{{/openApiNullable}}
<jackson-databind-version>2.13.4.2</jackson-databind-version>
<jackson-databind-version>2.14.3</jackson-databind-version>
{{#useJakartaEe}}
<jakarta-annotation-version>2.1.1</jakarta-annotation-version>
{{/useJakartaEe}}

View File

@@ -126,6 +126,9 @@ public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}}{{#vendorExtensi
{{#isArray}}
public {{classname}} add{{nameInCamelCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
if (this.{{name}} == null) {
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}};
}
this.{{name}}.add({{name}}Item);
return this;
}
@@ -133,6 +136,9 @@ public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}}{{#vendorExtensi
{{#isMap}}
public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
if (this.{{name}} == null) {
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}};
}
this.{{name}}.put(key, {{name}}Item);
return this;
}

View File

@@ -11,12 +11,14 @@ import java.net.URISyntaxException;
import java.util.Map;
import java.util.List;
import com.amazonaws.DefaultRequest;
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AnonymousAWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.http.HttpMethodName;
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.signer.Aws4Signer;
import software.amazon.awssdk.auth.signer.params.Aws4SignerParams;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.regions.Region;
import okio.Buffer;
@@ -28,11 +30,11 @@ public class AWS4Auth implements Authentication {
private String service;
public AWS4Auth() {
this.credentials = new AnonymousAWSCredentials();
this.credentials = AnonymousCredentialsProvider.create().resolveCredentials();
}
public void setCredentials(String accessKey, String secretKey) {
this.credentials = new BasicAWSCredentials(accessKey, secretKey);
this.credentials = AwsBasicCredentials.create(accessKey, secretKey);
}
public void setRegion(String region) {
@@ -44,28 +46,50 @@ public class AWS4Auth implements Authentication {
}
@Override
public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams, Map<String, String> cookieParams,
String payload, String method, URI uri) throws ApiException {
public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams,
Map<String, String> cookieParams, String payload, String method, URI uri)
throws ApiException {
DefaultRequest<String> signableRequest = new DefaultRequest<>(this.service);
SdkHttpFullRequest.Builder requestBuilder =
SdkHttpFullRequest.builder().uri(uri).method(SdkHttpMethod.fromValue(method));
signableRequest.setContent(new ByteArrayInputStream(payload.getBytes()));
ContentStreamProvider provider = new ContentStreamProvider() {
@Override
public InputStream newStream() {
InputStream is = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
return is;
}
};
signableRequest.setHttpMethod(HttpMethodName.valueOf(method));
URI targetUri = null;
try {
targetUri = new URI(uri.getScheme(), "", uri.getHost(), uri.getPort(), "", "", "");
} catch (URISyntaxException e) {
return;
requestBuilder = requestBuilder.contentStreamProvider(provider);
SdkHttpFullRequest signableRequest = sign(requestBuilder);
Map<String, String> headers = signableRequest.headers().entrySet().stream()
.collect(Collectors.toMap(s -> s.getKey(), e -> e.getValue().get(0)));
headerParams.putAll(headers);
}
/**
* AWS Signature Version 4 signing.
*
* @param request {@link SdkHttpFullRequest.Builder}
* @return {@link SdkHttpFullRequest}
*/
private SdkHttpFullRequest sign(final SdkHttpFullRequest.Builder request) {
SdkHttpFullRequest req = request.build();
if (this.service != null && this.region != null && this.credentials != null) {
Aws4SignerParams params = Aws4SignerParams.builder().signingName(this.service)
.signingRegion(Region.of(this.region)).awsCredentials(this.credentials).build();
Aws4Signer signer = Aws4Signer.create();
req = signer.sign(req, params);
}
signableRequest.setEndpoint(targetUri);
signableRequest.setResourcePath(uri.getPath());
AWS4Signer signer = new AWS4Signer(false);
signer.setServiceName(this.service);
signer.setRegionName(this.region);
signer.sign(signableRequest, credentials);
headerParams.putAll(signableRequest.getHeaders());
return req;
}
}

Some files were not shown because too many files have changed in this diff Show More