Compare commits

..

50 Commits

Author SHA1 Message Date
devhl
a60677705f why do i have to build again? 2023-01-28 23:39:07 -05:00
devhl
a5cf2fac8f build all samples 2023-01-28 23:17:48 -05:00
devhl
70f4fcc872 build more csharp samples 2023-01-28 22:58:05 -05:00
devhl
6043942c1b fixed serialization of nullable guids 2023-01-28 22:43:49 -05:00
devhl-labs
57546d49c2 renamed json converter variables (#14555) 2023-01-29 10:58:53 +08:00
Beppe Catanese
1c157a2847 Support examples in Response Content (#14336)
* Add examples map and overload constructor

* Create CodegenMediaType with examples

* Add test
2023-01-28 12:42:00 +08:00
Martin Delille
03299528e9 Add conan badge (#14537) 2023-01-28 12:12:20 +08:00
bgong-mdsol
47813a88a2 update imports for enum (#14546) 2023-01-28 12:10:59 +08:00
itaru2622
4ffdadfbcc [python-nextgen] fix issue on API example doc autogeneration (#14539)
* [python-nextgen] fix template to make auto-generated example runnable when spec has no auth methods

* update samples with ./bin/generate-samples.sh

* add unit test code
2023-01-28 12:03:17 +08:00
DevFlorian
6a2d8d23da #8792 [Java] [jaxrs-cxf] "useAbstractionForFiles" config option for jaxrs-cxf (#14316)
* [REQ] Add equals and hashcode to java-cxf pojo #12519

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* [Java] Use abstraction for files for jaxrs-cxf #8792

* fix sample

* fix sample

---------

Co-authored-by: FWermelskirchen <fwermelskirchen@eitco.de>
2023-01-28 11:37:08 +08:00
Oleh Kurpiak
ac5134acf3 [Java] fix JsonTypeName import (#14474) (fix #12524) 2023-01-25 14:39:58 +02:00
Michael Ramstein
5047273f1e [elixir] Properly map AnyType (#14497) 2023-01-24 07:48:49 +01:00
tjbdev
82ac92aed6 [elixir] connection.ex typo fix (#14512) 2023-01-24 07:12:32 +01:00
Michael Ramstein
ccbea26390 [elixir] Fixes issue with setting Header parameters (#14511)
* Fixes issue with request not beeing struct of Tesla.Env when setting a header parameter.
2023-01-23 22:03:05 +01:00
William Cheng
90e468b9a3 [java] Fix template logic related to supportUrlQuery (#14496)
* [java] Fix template logic related to supportUrlQuery

Generated models for arrays marked with uniqueItems: true (which end up as a Set<> in java) won't
compile because the templates are in some places using .get(i) on the sets.

Also, when the supportUrlQuery property is present in the additionalProperties map the
resulting value will be read using the key SUPPORT_STREAMING instead of 'supportUrlQuery'.

* fix NPE

Co-authored-by: Björgvin <bjorgvino@gmail.com>
2023-01-21 11:10:30 +08:00
devhl-labs
d4c8c97e19 [csharp-netcore] Pipeline fix (#14495)
* trying to fix pipeline

* forcing pipeline to run

* reverting change to wrong branch

* forcing pipeline to run

* reverting change
2023-01-21 10:46:42 +08:00
William Cheng
5e7d31a83b add a rule to keep only the first tag (#14465) 2023-01-20 15:50:31 +08:00
William Cheng
4ecb9f4186 [java][native] Fix urlQuery string method in oneOf (#14488)
* better tests, fix oneOf in urlquery string method

* update samples

* update
2023-01-20 01:57:32 +08:00
Ian Cubbon
6e780218ad [Go] Client Models using AllOf, OneOf, or AnyOf Correctly Include time and os imports (Attempt 2) (#14459)
* Currently, if a Model is an allOf the time and os imports are not correctly added to the generated file. This was introduced recently with a fix to not include those imports when the model is a composedSchema #13833. The logic in that fix was just slightly off as an allOf should be treated the same as a standard model.

If a model is an AllOf or does not have any composed schemas at all, the sub-models are in-lined defined in the struct. In this case, the standard logic of including the time and os imports apply.

If a model is a OneOf or AnyOf, the sub-models are included as pointers to the defined model. In this case, do not include those items in the logic of including time and os imports.

* Update example to include a time in an allOf

* Add back the accidentally removed nil check
2023-01-20 01:53:19 +08:00
William Cheng
6cd7989e9e [Java][native][apache-httpclient] Update toUrlQueryString to support form style for object (#14478)
* update toUrlQueryString

* add new files

* minor bug fixes

* support object in query parameter - java apache httpclient

* rename variable - java native

* update samples

* fix try catch
2023-01-19 16:13:51 +08:00
William Cheng
d1cde7febe Add 2 rules to OpenAPI Normalizer (#14463)
* add REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIIES_ONLY

* add rules to simplify anyOf

* fix rules, update docs

* remove test

* fix doc
2023-01-17 21:27:57 +08:00
Johnny Marnell
c912bae3bc [Spring] Fix bean name collisions (#14092) (fix #14094)
* Use correct Pascal case for java enum

* Uniquely name @Bean annotations

* Use existing mustache var instead, run generate files

* rebase, re-run generators

* try to undo botched rebase/merge

* Attempt to manually undo whatever is going on w/ build, oops

* Attempt to manually undo whatever is going on w/ build, oops
2023-01-17 11:24:15 +02:00
Vikrant Balyan
9f502930ea [Go] Adds a sha256 configuration option to hs2019 (#14467)
* enables configuration of sha256 with hs2019

* committing generated examples

Co-authored-by: Aanisha Mishra <aanisha.mishra05@gmail.com>
Co-authored-by: Sebastien Rosset <serosset@cisco.com>
2023-01-16 23:21:53 +08:00
Marvin Rensing
4cd080762a [Java][Spring] fix RequestPart/RequestParam handling on multipart request for arrays (#14450) (fix #14449) 2023-01-16 11:39:51 +02:00
Ian Cubbon
74073df27c [GO][Client] Use a *os.File for the API Client when uploading and downloading (#14340)
* Change the return type of a file back to a pointer

* Change the api template to handle not double pointer-ing return types of os.File

* Fix unit tests

* Couple more unit test fixes
2023-01-16 16:51:04 +08:00
Oleh Kurpiak
27137e75ce [Java][Spring] fix ParameterObject import for Spring Boot 3 (#14454)
fix #14077
2023-01-14 08:00:32 -08:00
Paul Parenko
be87382fde [Java][Spring] Fix #14398 springboot 3 schema required (#14402)
* fix depricated @Schema(required) since swagger 2.2.5

* use same swagger-annotations version which is used by swagger-core which is a dependency of springdoc

* generated java sampes
2023-01-14 06:59:33 -08:00
philkild
7958990254 Add CancellationToken to generated aspnetcore controller methods. (#14326) 2023-01-14 22:15:53 +08:00
Ian Cubbon
92775ceffc [Go] [Client] Don't Explode Query Params (#14447)
* If the collection type is csv, that means 'dont explode the query params'.

* Simplify the logic just a tad

* url.Values -> Has was added in go1.17 but there are CI tests running at 1.16
2023-01-14 00:48:27 +08:00
Bruno Coelho
d348754399 [kotlin][client] add info if endpoints requires authentication or not (#14445)
* [kotlin][client] add info if endpoints requires authentication or not

* [kotlin][client] update sample projects

* [kotlin][client] add info if endpoints requires authentication or not

* [kotlin][client] update sample projects
2023-01-13 10:29:27 +00:00
Bruno Coelho
b6ad68baca [swift5][client] - fix combine warning (#14444)
* [swift5][client] - fix combine warning

* [swift5][client] - fix combine warning

* [swift5][client] - update samples
2023-01-13 10:29:00 +00:00
William Cheng
079ad1742e update useRuntimeException description (#14452) 2023-01-13 17:38:31 +08:00
William Cheng
cf4f2c76b2 Use inline allof instead of $ref in echo test (#14429)
* use inline allof instead of $ref in echo test

* update samples

* update samples

* fix tests
2023-01-13 17:21:28 +08:00
Sebastian Saip
ed2029f863 [Java][Microprofile] fix useRuntimeException (#14409) (#14414)
Co-authored-by: Sebastian Saip <sebastian.saip@senacor.com>
2023-01-13 15:42:07 +08:00
devhl-labs
8abc750c0e [csharp-netcore] Added isNew property to CodegenProperty (#14412)
* added isNew property to CodegenModel

* build all samples
2023-01-13 14:43:33 +08:00
William Cheng
9fae221f1d [Java][okhttp-gson] add echo client test (#14442)
* add echo api tests for java okhttp client

* test okhttp gson echo client in jdk8 workflow

* update samples
2023-01-13 00:15:29 +08:00
Bruno Coelho
b1f8f976c0 [swift5][client] - enable swift unit tests (#14441) 2023-01-12 15:10:15 +00:00
William Cheng
a584f32d68 Add workflow to test java apache client with jdk8 (#14437)
* add workflow to test java apache client with jdk8

* fix url encode issue with jdk8

* update samples

* minor improvements in java native client

* minor fix
2023-01-12 22:12:08 +08:00
Paul Parenko
c2c91e2d2e [Java][Spring] Fix #14362 when useSpringBoot3=true, then useJakartaEe=true (#14373) 2023-01-12 19:54:42 +08:00
Oleh Kurpiak
076b88429e [Java][Spring] fix param docs (#14426) 2023-01-12 19:53:01 +08:00
Chao Yang
e1e291bc12 [Crystal] Skip primitive types from ModelImportMap (#14436)
* Support requiring models in crystal lang

* Return null instead of empty string
2023-01-12 19:42:33 +08:00
Bruno Coelho
e8811ecd28 [swift5][client] - simplify async await (#14430)
* [swift5][client] - simplify async await

* [swift5][client] - update sample projects

* [swift5][client] - add more tests
2023-01-12 10:55:41 +00:00
William Cheng
cffacc8023 fix deploy in travis (#14428) 2023-01-12 01:05:52 +08:00
Tino Fuhrmann
a31b5b119e Documentation of Configuration/ConfigurationParameter for consolidated TypeScript generator (#10283)
* Added additional documentation for configuration object

* Regenerate samples

* Added exemplary usage of API to README.md

* Updated README, refined wording

* Added example for calling the API

* Regenerated samples

* Updated samples
2023-01-11 15:18:53 +01:00
Oleh Kurpiak
5dbfea6ecc [Java][Spring] fix default response code (#14399) 2023-01-11 20:34:58 +08:00
William Cheng
50e295e3c6 Fix missing import in allOf query parameters (#14408)
* add test for allOf in query parameter

* fix missing import in allof query parameter

* update samples

* update samples
2023-01-11 20:29:13 +08:00
William Cheng
3f96cdb756 Fix circleci build failure (node1) and Travis build failure (#14425)
* move python fastapi test to another node

* fix travis build

* fix install

* fix install

* fix install

* skip php test

* fix

* use trusty

* test bionic

* fix install

* fix pom

* skip perl test

* skip fastapitest
2023-01-11 20:28:53 +08:00
William Cheng
e825f27b0b [java][apache-httpclient] Add deep object url query parameter support (#14417)
* add deep object url query parameter to java apache-httpclient

* update doc string
2023-01-11 11:04:14 +08:00
yosshi4486
4044e724c0 [Swift5] Add an async execute API to RequestBuilder<T> (#14416)
* Add async `execute` interface

* Update samples

Run `./bin/generate-samples.sh`

* Add an explicit `self`

I forgot to add it

* Add an availability condition
2023-01-10 17:05:52 +00:00
Maxime Dufour
c6ea564600 [Java][Client Default] Support of AWS Signature V4 (#14287)
* Add support of AWSV4 Signature in Java

* Add Petstore sample for AWSV4 Signature

* Update other sample examples

* Sync Documentation and sample

* Specify only available for okhttp-gson in doc
2023-01-10 19:29:20 +08:00
1770 changed files with 73702 additions and 10107 deletions

View File

@@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 2.1.*
dotnet-version: 3.1.*
- name: Build
working-directory: ${{ matrix.sample }}
run: dotnet build Org.OpenAPITools.sln

View File

@@ -0,0 +1,48 @@
name: Java Client (Echo API) JDK8
on:
push:
paths:
- samples/client/echo_api/java/apache-httpclient/**
- samples/client/echo_api/java/feign-gson/**
- samples/client/echo_api/java/okhttp-gson/**
pull_request:
paths:
- samples/client/echo_api/java/apache-httpclient/**
- samples/client/echo_api/java/feign-gson/**
- samples/client/echo_api/java/okhttp-gson/**
jobs:
build:
name: Build Java Client JDK8
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sample:
# clients
- samples/client/echo_api/java/apache-httpclient
- samples/client/echo_api/java/feign-gson
- samples/client/echo_api/java/okhttp-gson
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: 8
- name: Cache maven dependencies
uses: actions/cache@v3
env:
cache-name: maven-repository
with:
path: |
~/.m2
key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }}
- name: Setup node.js
uses: actions/setup-node@v3
- name: Run echo server
run: |
git clone https://github.com/wing328/http-echo-server -b openapi-generator-test-server
(cd http-echo-server && npm install && npm start &)
- name: Build
working-directory: ${{ matrix.sample }}
run: mvn clean package

View File

@@ -50,15 +50,16 @@ before_install:
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) edge"
- sudo apt-get update
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
#- sudo apt-get install -qqy --no-install-recommends google-chrome-stable
#- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- mkdir -vp ~/.docker/cli-plugins/
- curl --silent -L "https://github.com/docker/buildx/releases/download/v0.3.0/buildx-v0.3.0.linux-amd64" > ~/.docker/cli-plugins/docker-buildx
- chmod a+x ~/.docker/cli-plugins/docker-buildx
# to run petstore server locally via docker
- echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin || true
- docker pull swaggerapi/petstore
- docker run -d -e SWAGGER_HOST=http://petstore.swagger.io -e SWAGGER_BASE_PATH=/v2 -p 80:8080 swaggerapi/petstore
- docker ps -a
#- echo "$DOCKER_HUB_PASSWORD" | docker login --username=$DOCKER_HUB_USERNAME --password-stdin || true
#- docker pull swaggerapi/petstore
#- docker run -d -e SWAGGER_HOST=http://petstore.swagger.io -e SWAGGER_BASE_PATH=/v2 -p 80:8080 swaggerapi/petstore
#- docker ps -a
# comment out crystal installation as the tests will run on circleci or github action instead
# install crystal
#- echo 'deb http://download.opensuse.org/repositories/devel:/languages:/crystal/xUbuntu_16.04/ /' | sudo tee /etc/apt/sources.list.d/devel:languages:crystal.list
@@ -69,11 +70,11 @@ before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.22.0
- export PATH="$HOME/.yarn/bin:$PATH"
# install rust
- curl https://sh.rustup.rs -sSf | sh -s -- -y -v
# required when sudo: required for the Ruby petstore tests
- gem install bundler -v 2.3.26
# set python 3.6.3 as default
- source ~/virtualenv/python3.6/bin/activate
#- curl https://sh.rustup.rs -sSf | sh -s -- -y -v
## required when sudo: required for the Ruby petstore tests
#- gem install bundler -v 2.3.26
## set python 3.6.3 as default
#- source ~/virtualenv/python3.6/bin/activate
# -- skip bash test to shorten build time
# Add bats test framework and cURL for Bash script integration tests
#- sudo add-apt-repository ppa:duggan/bats --yes
@@ -88,18 +89,18 @@ before_install:
#- sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
#- sudo apt-get update
#- sudo apt-get install dart
# switch to php7
- sudo apt-get install libonig-dev libzip-dev
- git clone https://github.com/php-build/php-build $(phpenv root)/plugins/php-build
- git clone https://github.com/ngyuki/phpenv-composer.git $(phpenv root)/plugins/phpenv-composer
- if [ $(ls -A "$HOME/.phpenv/versions/8.1.4" | wc -l) -eq 0 ]; then
phpenv install 8.1.4;
fi;
- phpenv rehash
- phpenv versions
#- phpenv global 7.2.15
- phpenv global 8.1.4
- php -v
# switch to php8
#- sudo apt-get install -f libonig-dev libzip-dev
#- git clone https://github.com/php-build/php-build $(phpenv root)/plugins/php-build
#- git clone https://github.com/ngyuki/phpenv-composer.git $(phpenv root)/plugins/phpenv-composer
#- if [ $(ls -A "$HOME/.phpenv/versions/8.1.4" | wc -l) -eq 0 ]; then
# phpenv install 8.1.4;
# fi;
#- phpenv rehash
#- phpenv versions
##- phpenv global 7.2.15
#- phpenv global 8.1.4
#- php -v
# comment out below as installation failed in travis
# Add rebar3 build tool and recent Erlang/OTP for Erlang petstore server tests.
# - Travis CI does not support rebar3 [yet](https://github.com/travis-ci/travis-ci/issues/6506#issuecomment-275189490).
@@ -107,15 +108,15 @@ before_install:
# - . ~/otp/18.2.1/activate && erl -version
#- curl -f -L -o ./rebar3 https://s3.amazonaws.com/rebar3/rebar3 && chmod +x ./rebar3 && ./rebar3 version && export PATH="${TRAVIS_BUILD_DIR}:$PATH"
# install C++ tools
- sudo apt install -y --no-install-recommends valgrind cmake build-essential
- cmake --version
#- sudo apt install -y --no-install-recommends valgrind cmake build-essential
#- cmake --version
# install Qt5
#- sudo apt install -y --no-install-recommends qt5-default
# install boost
- sudo apt install -y --no-install-recommends libboost-all-dev
#- sudo apt install -y --no-install-recommends libboost-all-dev
# perl dep
- cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
- cpanm --quiet --no-interactive Test::Exception Test::More Log::Any LWP::UserAgent URI::Query Module::Runtime DateTime Module::Find Moose::Role JSON || echo "Ignored failure from cpanm"
#- cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
#- cpanm --quiet --no-interactive Test::Exception Test::More Log::Any LWP::UserAgent URI::Query Module::Runtime DateTime Module::Find Moose::Role JSON || echo "Ignored failure from cpanm"
# show host table to confirm petstore.swagger.io is mapped to localhost
- cat /etc/hosts
# show java version
@@ -127,8 +128,8 @@ before_install:
fi;
- pushd .; cd website; yarn install; popd
# install Deno
- sh -s v1.6.2 < ./CI/deno_install.sh
- export PATH="$HOME/.deno/bin:$PATH"
#- sh -s v1.6.2 < ./CI/deno_install.sh
#- export PATH="$HOME/.deno/bin:$PATH"
install:
# Add Godeps dependencies to GOPATH and PATH
@@ -150,7 +151,7 @@ script:
# run integration tests defined in maven pom.xml
# WARN: Travis will timeout after 10 minutes of no stdout/stderr activity, which is problematic with mvn --quiet.
- mvn -e --no-snapshot-updates --quiet --batch-mode --show-version clean install -Dorg.slf4j.simpleLogger.defaultLogLevel=error
- mvn -e --no-snapshot-updates --quiet --batch-mode --show-version verify -Psamples -Dorg.slf4j.simpleLogger.defaultLogLevel=error
#- mvn -e --no-snapshot-updates --quiet --batch-mode --show-version verify -Psamples -Dorg.slf4j.simpleLogger.defaultLogLevel=error
after_success:
# push to maven repo
- if [ $SONATYPE_USERNAME ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then

View File

@@ -3,7 +3,13 @@
<div align="center">
[![Stable releases in Maven Central](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/org/openapitools/openapi-generator/maven-metadata.xml.svg)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.openapitools%22%20AND%20a%3A%22openapi-generator%22) [![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-orange)](./LICENSE) [![Open Collective backers](https://img.shields.io/opencollective/backers/openapi_generator?color=orange&label=OpenCollective%20Backers)](https://opencollective.com/openapi_generator) [![Join the Slack chat room](https://img.shields.io/badge/Slack-Join%20the%20chat%20room-orange)](https://join.slack.com/t/openapi-generator/shared_invite/zt-12jxxd7p2-XUeQM~4pzsU9x~eGLQqX2g) [![Follow OpenAPI Generator Twitter account to get the latest update](https://img.shields.io/twitter/follow/oas_generator.svg?style=social&label=Follow)](https://twitter.com/oas_generator) [![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/OpenAPITools/openapi-generator)
[![Stable releases in Maven Central](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/org/openapitools/openapi-generator/maven-metadata.xml.svg)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.openapitools%22%20AND%20a%3A%22openapi-generator%22)
[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-orange)](./LICENSE)
[![Open Collective backers](https://img.shields.io/opencollective/backers/openapi_generator?color=orange&label=OpenCollective%20Backers)](https://opencollective.com/openapi_generator)
[![Join the Slack chat room](https://img.shields.io/badge/Slack-Join%20the%20chat%20room-orange)](https://join.slack.com/t/openapi-generator/shared_invite/zt-12jxxd7p2-XUeQM~4pzsU9x~eGLQqX2g)
[![Follow OpenAPI Generator Twitter account to get the latest update](https://img.shields.io/twitter/follow/oas_generator.svg?style=social&label=Follow)](https://twitter.com/oas_generator)
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/OpenAPITools/openapi-generator)
[![Conan Center](https://shields.io/conan/v/openapi-generator)](https://conan.io/center/openapi-generator)
</div>

View File

@@ -1,7 +1,7 @@
generatorName: java
outputDir: samples/client/petstore/java/native-async
library: native
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/java/native/petstore-with-fake-endpoints-models-for-testing-with-http-signature.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
additionalProperties:
artifactId: petstore-native

View File

@@ -1,7 +1,7 @@
generatorName: java
outputDir: samples/client/petstore/java/native
library: native
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/java/native/petstore-with-fake-endpoints-models-for-testing-with-http-signature.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
additionalProperties:
artifactId: petstore-native

View File

@@ -0,0 +1,11 @@
generatorName: java
outputDir: samples/client/petstore/java/okhttp-gson-awsv4signature
library: okhttp-gson
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
additionalProperties:
artifactId: okhttp-gson-awsv4signature
hideGenerationTimestamp: "true"
useOneOfDiscriminatorLookup: "true"
disallowAdditionalPropertiesIfNotPresent: false
withAWSV4Signature: true

View File

@@ -0,0 +1,8 @@
generatorName: java
outputDir: samples/client/echo_api/java/okhttp-gson
#library: okhttp-gson
inputSpec: modules/openapi-generator/src/test/resources/3_0/echo_api.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
additionalProperties:
artifactId: echo-api-okhttp-gson
hideGenerationTimestamp: "true"

View File

@@ -456,11 +456,24 @@ Note: Only arrayItemSuffix, mapItemSuffix are supported at the moment. `SKIP_SCH
OpenAPI Normalizer (off by default) transforms the input OpenAPI doc/spec (which may not perfectly conform to the specification) to make it workable with OpenAPI Generator. Here is a list of rules supported:
- `REF_AS_PARENT_IN_ALLOF`: when set to `true`, child schemas in `allOf` is considered a parent if it's a `$ref` (instead of inline schema)
- `REF_AS_PARENT_IN_ALLOF`: when set to `true`, child schemas in `allOf` is considered a parent if it's a `$ref` (instead of inline schema).
Example:
```
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/allOf_extension_parent.yaml -o /tmp/java-okhttp/ --additional-properties hideGenerationTimestamp="true" --openapi-normalizer REF_AS_PARENT_IN_ALLOF=true
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/allOf_extension_parent.yaml -o /tmp/java-okhttp/ --openapi-normalizer REF_AS_PARENT_IN_ALLOF=true
```
- `REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY`: when set to `true`, oneOf/anyOf schema with only required properies only in a schema with properties will be removed. [(example)](modules/openapi-generator/src/test/resources/3_0/removeAnyOfOneOfAndKeepPropertiesOnly_test.yaml)
Example:
```
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/removeAnyOfOneOfAndKeepPropertiesOnly_test.yaml -o /tmp/java-okhttp/ --openapi-normalizer REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY=true
```
- `SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING`: when set to `true`, simplify anyOf schema with string and enum of string to just `string`
Example:
```
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/simplifyAnyOfStringAndEnumString_test.yaml -o /tmp/java-okhttp/ --openapi-normalizer SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING=true
```

View File

@@ -45,6 +45,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>AnyType</li>
<li>Atom</li>
<li>Boolean</li>
<li>DateTime</li>
@@ -56,6 +57,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
<li>PID</li>
<li>String</li>
<li>Tuple</li>
<li>any()</li>
<li>map()</li>
</ul>
@@ -103,7 +105,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|Uuid|✗|
|Array|✓|OAS2,OAS3
|Null|✗|OAS3
|AnyType||OAS2,OAS3
|AnyType||OAS2,OAS3
|Object|✓|OAS2,OAS3
|Maps|✓|ToolingExtension
|CollectionFormat|✓|OAS2

View File

@@ -95,7 +95,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
|useOptional|Use Optional container for optional parameters| |false|
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports).| |false|
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
|useSpringController|Annotate the generated API as a Spring Controller| |false|
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|
|useTags|use tags for creating interface and controller classnames| |false|

View File

@@ -87,11 +87,12 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|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. Only jersey2, jersey3, native, okhttp-gson support this option.| |false|
|usePlayWS|Use Play! Async HTTP client (Play WS API)| |false|
|useReflectionEqualsHashCode|Use org.apache.commons.lang3.builder for equals and hashCode in the models. WARNING: This will fail under a security manager, unless the appropriate permissions are set up correctly and also there's potential performance impact.| |false|
|useRuntimeException|Use RuntimeException instead of Exception| |false|
|useRuntimeException|Use RuntimeException instead of Exception. Only jersey, jersey2, jersey3, okhttp-gson, vertx, microprofile support this option.| |false|
|useRxJava2|Whether to use the RxJava2 adapter with the retrofit2 library. IMPORTANT: This option has been deprecated.| |false|
|useRxJava3|Whether to use the RxJava3 adapter with the retrofit2 library. IMPORTANT: This option has been deprecated.| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter. ONLY jersey2, jersey3, okhttp-gson support this option.| |false|
|webclientBlockingOperations|Making all WebClient operations blocking(sync). Note that if on operation 'x-webclient-blocking: false' then such operation won't be sync| |false|
|withAWSV4Signature|whether to include AWS v4 signature support (only available for okhttp-gson library)| |false|
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|
## SUPPORTED VENDOR EXTENSIONS

View File

@@ -65,6 +65,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|sourceFolder|source folder for generated code| |src/gen/java|
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk.| |false|
|useBeanValidation|Use BeanValidation API annotations| |false|
|useGenericResponse|Use generic response| |false|
|useGzipFeatureForTests|Use Gzip Feature for tests| |false|

View File

@@ -78,6 +78,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|testDataFile|JSON file to contain generated test data| |null|
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|title|a title describing the application| |OpenAPI Server|
|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk.| |false|
|useAnnotatedBasePath|Use @Path annotations for basePath| |false|
|useBeanValidation|Use BeanValidation API annotations| |true|
|useBeanValidationFeature|Use BeanValidation Feature| |false|

View File

@@ -73,6 +73,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|sourceFolder|source folder for generated code| |src/gen/java|
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|title|a title describing the application| |OpenAPI Server|
|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk.| |false|
|useAnnotatedBasePath|Use @Path annotations for basePath| |false|
|useBeanValidation|Use BeanValidation API annotations| |true|
|useBeanValidationFeature|Use BeanValidation Feature| |false|

View File

@@ -88,7 +88,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
|useOptional|Use Optional container for optional parameters| |false|
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports).| |false|
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
|useSpringController|Annotate the generated API as a Spring Controller| |false|
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|
|useTags|use tags for creating interface and controller classnames| |false|

View File

@@ -1,13 +1,17 @@
package org.openapitools.codegen;
import io.swagger.v3.oas.models.examples.Example;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
public class CodegenMediaType {
private CodegenProperty schema;
private LinkedHashMap<String, CodegenEncoding> encoding;
private HashMap<String, SchemaTestCase> testCases = new HashMap<>();
private Map<String, Example> examples = null;
public CodegenMediaType(CodegenProperty schema, LinkedHashMap<String, CodegenEncoding> encoding, HashMap<String, SchemaTestCase> testCases) {
this.schema = schema;
@@ -17,6 +21,11 @@ public class CodegenMediaType {
}
}
public CodegenMediaType(CodegenProperty schema, LinkedHashMap<String, CodegenEncoding> encoding, HashMap<String, SchemaTestCase> testCases, Map<String, Example> examples) {
this(schema, encoding, testCases);
this.examples = examples;
}
public CodegenProperty getSchema() {
return schema;
}
@@ -27,6 +36,10 @@ public class CodegenMediaType {
public HashMap<String, SchemaTestCase> getTestCases() { return testCases; }
public Map<String, Example> getExamples() {
return examples;
}
public String toString() {
final StringBuilder sb = new StringBuilder("CodegenMediaType{");
sb.append("schema=").append(schema);

View File

@@ -157,6 +157,7 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
public boolean isSelfReference;
public boolean isCircularReference;
public boolean isDiscriminator;
public boolean isNew; // true when this property overrides an inherited property
public List<String> _enum;
public Map<String, Object> allowableValues;
// If 'additionalProperties' is not set, items is null.
@@ -1063,6 +1064,7 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
sb.append(", isSelfReference=").append(isSelfReference);
sb.append(", isCircularReference=").append(isCircularReference);
sb.append(", isDiscriminator=").append(isDiscriminator);
sb.append(", isNew=").append(isNew);
sb.append(", _enum=").append(_enum);
sb.append(", allowableValues=").append(allowableValues);
sb.append(", items=").append(items);
@@ -1153,6 +1155,7 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
isSelfReference == that.isSelfReference &&
isCircularReference == that.isCircularReference &&
isDiscriminator == that.isDiscriminator &&
isNew == that.isNew &&
hasValidation == that.hasValidation &&
isInherited == that.isInherited &&
isXmlAttribute == that.isXmlAttribute &&
@@ -1230,7 +1233,7 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBinary, isFile,
isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isFreeFormObject,
isArray, isMap, isEnum, isInnerEnum, isEnumRef, isAnyType, isReadOnly, isWriteOnly, isNullable, isShort,
isUnboundedInteger, isSelfReference, isCircularReference, isDiscriminator, _enum,
isUnboundedInteger, isSelfReference, isCircularReference, isDiscriminator, isNew, _enum,
allowableValues, items, mostInnerItems, additionalProperties, vars, requiredVars,
vendorExtensions, hasValidation, isInherited, discriminatorValue, nameInCamelCase,
nameInSnakeCase, enumName, maxItems, minItems, isXmlAttribute, xmlPrefix, xmlName,

View File

@@ -470,6 +470,35 @@ public class DefaultCodegen implements CodegenConfig {
@Override
@SuppressWarnings("static-method")
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
for (Map.Entry<String, ModelsMap> entry : objs.entrySet()) {
CodegenModel model = ModelUtils.getModelByName(entry.getKey(), objs);
for (CodegenProperty property : model.allVars){
property.isNew = codegenPropertyIsNew(model, property);
}
for (CodegenProperty property : model.vars){
property.isNew = codegenPropertyIsNew(model, property);
}
for (CodegenProperty property : model.readWriteVars){
property.isNew = codegenPropertyIsNew(model, property);
}
for (CodegenProperty property : model.optionalVars){
property.isNew = codegenPropertyIsNew(model, property);
}
for (CodegenProperty property : model.parentVars){
property.isNew = codegenPropertyIsNew(model, property);
}
for (CodegenProperty property : model.requiredVars){
property.isNew = codegenPropertyIsNew(model, property);
}
for (CodegenProperty property : model.readOnlyVars){
property.isNew = codegenPropertyIsNew(model, property);
}
for (CodegenProperty property : model.nonNullableVars){
property.isNew = codegenPropertyIsNew(model, property);
}
}
if (this.useOneOfInterfaces) {
// First, add newly created oneOf interfaces
for (CodegenModel cm : addOneOfInterfaces) {
@@ -524,6 +553,12 @@ public class DefaultCodegen implements CodegenConfig {
return objs;
}
private boolean codegenPropertyIsNew(CodegenModel model, CodegenProperty property) {
return model.parentModel == null
? false
: model.parentModel.allVars.stream().anyMatch(p -> p.name.equals(property.name) && (p.dataType.equals(property.dataType) == false || p.datatypeWithEnum.equals(property.datatypeWithEnum) == false));
}
/**
* Return a map from model name to Schema for efficient lookup.
*
@@ -5031,7 +5066,7 @@ public class DefaultCodegen implements CodegenConfig {
if (parameterModelName != null) {
codegenParameter.dataType = parameterModelName;
if (ModelUtils.isObjectSchema(parameterSchema)) {
if (ModelUtils.isObjectSchema(parameterSchema) || ModelUtils.isComposedSchema(parameterSchema)) {
codegenProperty.complexType = codegenParameter.dataType;
}
} else {
@@ -7201,7 +7236,7 @@ public class DefaultCodegen implements CodegenConfig {
}
}
CodegenMediaType codegenMt = new CodegenMediaType(schemaProp, ceMap, schemaTestCases);
CodegenMediaType codegenMt = new CodegenMediaType(schemaProp, ceMap, schemaTestCases, mt.getExamples());
cmtContent.put(contentType, codegenMt);
if (schemaProp != null) {
if (addSchemaImportsFromV3SpecLocations) {

View File

@@ -48,6 +48,21 @@ public class OpenAPINormalizer {
final String REF_AS_PARENT_IN_ALLOF = "REF_AS_PARENT_IN_ALLOF";
boolean enableRefAsParentInAllOf;
// when set to true, only keep the first tag in operation if there are more than one tag defined.
final String KEEP_ONLY_FIRST_TAG_IN_OPERATION = "KEEP_ONLY_FIRST_TAG_IN_OPERATION";
boolean enableKeepOnlyFirstTagInOperation;
// when set to true, complex composed schemas (a mix of oneOf/anyOf/anyOf and properties) with
// oneOf/anyOf containing only `required` and no properties (these are properties inter-dependency rules)
// are removed as most generators cannot handle such case at the moment
final String REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY = "REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY";
boolean removeAnyOfOneOfAndKeepPropertiesOnly;
// when set to true, oneOf/anyOf with either string or enum string as sub schemas will be simplified
// to just string
final String SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING = "SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING";
boolean simplifyAnyOfStringAndEnumString;
// ============= end of rules =============
/**
@@ -79,6 +94,18 @@ public class OpenAPINormalizer {
if (enableAll || "true".equalsIgnoreCase(rules.get(REF_AS_PARENT_IN_ALLOF))) {
enableRefAsParentInAllOf = true;
}
if (enableAll || "true".equalsIgnoreCase(rules.get(KEEP_ONLY_FIRST_TAG_IN_OPERATION))) {
enableKeepOnlyFirstTagInOperation = true;
}
if (enableAll || "true".equalsIgnoreCase(rules.get(REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY))) {
removeAnyOfOneOfAndKeepPropertiesOnly = true;
}
if (enableAll || "true".equalsIgnoreCase(rules.get(SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING))) {
simplifyAnyOfStringAndEnumString = true;
}
}
/**
@@ -127,6 +154,7 @@ public class OpenAPINormalizer {
}
for (Operation operation : operations) {
normalizeOperation(operation);
normalizeRequestBody(operation);
normalizeParameters(operation);
normalizeResponses(operation);
@@ -134,6 +162,15 @@ public class OpenAPINormalizer {
}
}
/**
* Normalizes operation
*
* @param operation Operation
*/
private void normalizeOperation(Operation operation) {
processKeepOnlyFirstTagInOperation(operation);
}
/**
* Normalizes schemas in content
*
@@ -235,7 +272,8 @@ public class OpenAPINormalizer {
if (schema == null) {
LOGGER.warn("{} not fount found in openapi/components/schemas.", schemaName);
} else {
normalizeSchema(schema, new HashSet<>());
Schema result = normalizeSchema(schema, new HashSet<>());
schemas.put(schemaName, result);
}
}
}
@@ -245,19 +283,20 @@ public class OpenAPINormalizer {
*
* @param schema Schema
* @param visitedSchemas a set of visited schemas
* @return Schema
*/
public void normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
if (schema == null) {
return;
return schema;
}
if (StringUtils.isNotEmpty(schema.get$ref())) {
// not need to process $ref
return;
return schema;
}
if ((visitedSchemas.contains(schema))) {
return; // skip due to circular reference
return schema; // skip due to circular reference
} else {
visitedSchemas.add(schema);
}
@@ -267,38 +306,47 @@ public class OpenAPINormalizer {
} else if (schema.getAdditionalProperties() instanceof Schema) { // map
normalizeSchema((Schema) schema.getAdditionalProperties(), visitedSchemas);
} else if (ModelUtils.isComposedSchema(schema)) {
ComposedSchema m = (ComposedSchema) schema;
if (m.getAllOf() != null && !m.getAllOf().isEmpty()) {
normalizeAllOf(m, visitedSchemas);
ComposedSchema cs = (ComposedSchema) schema;
if (ModelUtils.isComplexComposedSchema(cs)) {
cs = (ComposedSchema) normalizeComplexComposedSchema(cs, visitedSchemas);
}
if (m.getOneOf() != null && !m.getOneOf().isEmpty()) {
normalizeOneOf(m, visitedSchemas);
if (cs.getAllOf() != null && !cs.getAllOf().isEmpty()) {
return normalizeAllOf(cs, visitedSchemas);
}
if (m.getAnyOf() != null && !m.getAnyOf().isEmpty()) {
normalizeAnyOf(m, visitedSchemas);
if (cs.getOneOf() != null && !cs.getOneOf().isEmpty()) {
return normalizeOneOf(cs, visitedSchemas);
}
if (m.getProperties() != null && !m.getProperties().isEmpty()) {
normalizeProperties(m.getProperties(), visitedSchemas);
if (cs.getAnyOf() != null && !cs.getAnyOf().isEmpty()) {
return normalizeAnyOf(cs, visitedSchemas);
}
if (m.getAdditionalProperties() != null) {
if (cs.getProperties() != null && !cs.getProperties().isEmpty()) {
normalizeProperties(cs.getProperties(), visitedSchemas);
}
if (cs.getAdditionalProperties() != null) {
// normalizeAdditionalProperties(m);
}
return cs;
} else if (schema.getNot() != null) {// not schema
normalizeSchema(schema.getNot(), visitedSchemas);
} else if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
normalizeProperties(schema.getProperties(), visitedSchemas);
} else if (schema instanceof Schema) {
normalizeNonComposedSchema(schema, visitedSchemas);
normalizeSchemaWithOnlyProperties(schema, visitedSchemas);
} else {
throw new RuntimeException("Unknown schema type found in normalizer: " + schema);
}
return schema;
}
private void normalizeNonComposedSchema(Schema schema, Set<Schema> visitedSchemas) {
private void normalizeSchemaWithOnlyProperties(Schema schema, Set<Schema> visitedSchemas) {
// normalize non-composed schema (e.g. schema with only properties)
}
@@ -312,7 +360,7 @@ public class OpenAPINormalizer {
}
}
private void normalizeAllOf(Schema schema, Set<Schema> visitedSchemas) {
private Schema normalizeAllOf(Schema schema, Set<Schema> visitedSchemas) {
for (Object item : schema.getAllOf()) {
if (!(item instanceof Schema)) {
throw new RuntimeException("Error! allOf schema is not of the type Schema: " + item);
@@ -322,34 +370,55 @@ public class OpenAPINormalizer {
}
// process rules here
processUseAllOfRefAsParent(schema);
return schema;
}
private void normalizeOneOf(Schema schema, Set<Schema> visitedSchemas) {
for (Object item : schema.getAllOf()) {
private Schema normalizeOneOf(Schema schema, Set<Schema> visitedSchemas) {
for (Object item : schema.getOneOf()) {
if (!(item instanceof Schema)) {
throw new RuntimeException("Error! allOf schema is not of the type Schema: " + item);
}
// normalize oenOf sub schemas one by one
normalizeSchema((Schema) item, visitedSchemas);
}
// process rules here
return schema;
}
private void normalizeAnyOf(Schema schema, Set<Schema> visitedSchemas) {
for (Object item : schema.getAllOf()) {
private Schema normalizeAnyOf(Schema schema, Set<Schema> visitedSchemas) {
for (Object item : schema.getAnyOf()) {
if (!(item instanceof Schema)) {
throw new RuntimeException("Error! allOf schema is not of the type Schema: " + item);
}
// normalize anyOf sub schemas one by one
normalizeSchema((Schema) item, visitedSchemas);
}
// process rules here
// last rule to process as the schema may become String schema (not "anyOf") after the completion
return processSimplifyAnyOfStringAndEnumString(schema);
}
private Schema normalizeComplexComposedSchema(Schema schema, Set<Schema> visitedSchemas) {
processRemoveAnyOfOneOfAndKeepPropertiesOnly(schema);
return schema;
}
// ===================== a list of rules =====================
// all rules (fuctions) start with the word "process"
/**
* Child schemas in `allOf` is considered a parent if it's a `$ref` (instead of inline schema).
*
* @param schema Schema
*/
private void processUseAllOfRefAsParent(Schema schema) {
if (!enableRefAsParentInAllOf) {
if (!enableRefAsParentInAllOf && !enableAll) {
return;
}
@@ -380,5 +449,84 @@ public class OpenAPINormalizer {
}
}
}
/**
* Keep only first tag in the operation if the operation has more than
* one tag.
*
* @param operation Operation
*/
private void processKeepOnlyFirstTagInOperation(Operation operation) {
if (!enableKeepOnlyFirstTagInOperation) {
return;
}
if (operation.getTags() != null && !operation.getTags().isEmpty() && operation.getTags().size() > 1) {
// has more than 1 tag
String firstTag = operation.getTags().get(0);
operation.setTags(null);
operation.addTagsItem(firstTag);
}
}
/**
* If the schema contains anyOf/oneOf and properties, remove oneOf/anyOf as these serve as rules to
* ensure inter-dependency between properties. It's a workaround as such validation is not supported at the moment.
*
* @param schema Schema
*/
private void processRemoveAnyOfOneOfAndKeepPropertiesOnly(Schema schema) {
if (!removeAnyOfOneOfAndKeepPropertiesOnly && !enableAll) {
return;
}
if (((schema.getOneOf() != null && !schema.getOneOf().isEmpty())
|| (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty())) // has anyOf or oneOf
&& (schema.getProperties() != null && !schema.getProperties().isEmpty()) // has properties
&& schema.getAllOf() == null) { // not allOf
// clear oneOf, anyOf
schema.setOneOf(null);
schema.setAnyOf(null);
}
}
/**
* If the schema is anyOf and the sub-schemas are either string or enum of string,
* then simply it to just string as many generators do not yet support anyOf.
*
* @param schema Schema
* @return Schema
*/
private Schema processSimplifyAnyOfStringAndEnumString(Schema schema) {
if (!simplifyAnyOfStringAndEnumString && !enableAll) {
return schema;
}
Schema s0 = null, s1 = null;
if (schema.getAnyOf().size() == 2) {
s0 = ModelUtils.unaliasSchema(openAPI, (Schema) schema.getAnyOf().get(0));
s1 = ModelUtils.unaliasSchema(openAPI, (Schema) schema.getAnyOf().get(1));
} else {
return schema;
}
s0 = ModelUtils.getReferencedSchema(openAPI, s0);
s1 = ModelUtils.getReferencedSchema(openAPI, s1);
// find the string schema (not enum)
if (s0 instanceof StringSchema && s1 instanceof StringSchema) {
if (((StringSchema) s0).getEnum() != null) { // s0 is enum, s1 is string
return (StringSchema) s1;
} else if (((StringSchema) s1).getEnum() != null) { // s1 is enum, s0 is string
return (StringSchema) s0;
} else { // both are string
return schema;
}
} else {
return schema;
}
}
// ===================== end of rules =====================
}

View File

@@ -121,9 +121,9 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
typeMapping.put("date", "string");
typeMapping.put("DateTime", "time.Time");
typeMapping.put("password", "string");
typeMapping.put("File", "os.File");
typeMapping.put("file", "os.File");
typeMapping.put("binary", "os.File");
typeMapping.put("File", "*os.File");
typeMapping.put("file", "*os.File");
typeMapping.put("binary", "*os.File");
typeMapping.put("ByteArray", "string");
typeMapping.put("null", "nil");
// A 'type: object' OAS schema without any declared property is
@@ -505,13 +505,13 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
boolean addedReflectImport = false;
for (CodegenOperation operation : operations) {
// import "os" if the operation uses files
if (!addedOSImport && "os.File".equals(operation.returnType)) {
if (!addedOSImport && "*os.File".equals(operation.returnType)) {
imports.add(createMapping("import", "os"));
addedOSImport = true;
}
for (CodegenParameter param : operation.allParams) {
// import "os" if the operation uses files
if (!addedOSImport && "os.File".equals(param.dataType)) {
if (!addedOSImport && "*os.File".equals(param.dataType)) {
imports.add(createMapping("import", "os"));
addedOSImport = true;
}
@@ -634,9 +634,6 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
List<CodegenProperty> inheritedProperties = new ArrayList<>();
if (model.getComposedSchemas() != null) {
if (model.getComposedSchemas().getAllOf() != null) {
inheritedProperties.addAll(model.getComposedSchemas().getAllOf());
}
if (model.getComposedSchemas().getAnyOf() != null) {
inheritedProperties.addAll(model.getComposedSchemas().getAnyOf());
}
@@ -646,41 +643,31 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
}
List<CodegenProperty> codegenProperties = new ArrayList<>();
if(model.getIsModel() || model.getComposedSchemas() == null) {
// If the model is a model, use model.vars as it only
// contains properties the generated struct will own itself.
// If model is no model and it has no composed schemas use
// model.vars.
if(model.getComposedSchemas() == null || (model.getComposedSchemas() != null && model.getComposedSchemas().getAllOf() != null)) {
// If the model is an allOf or does not have any composed schemas, then we can use the model's properties.
codegenProperties.addAll(model.vars);
} else {
// If the model is no model, but is a
// allOf, anyOf or oneOf, add all first level options
// from allOf, anyOf or oneOf.
// anyOf or oneOf, add all first level options
// from anyOf or oneOf.
codegenProperties.addAll(inheritedProperties);
}
for (CodegenProperty cp : codegenProperties) {
if (!addedTimeImport && ("time.Time".equals(cp.dataType) ||
(cp.items != null && "time.Time".equals(cp.items.dataType)))) {
if (!addedTimeImport && ("time.Time".equals(cp.dataType) || (cp.items != null && "time.Time".equals(cp.items.dataType)))) {
imports.add(createMapping("import", "time"));
addedTimeImport = true;
}
if (!addedOSImport && ("os.File".equals(cp.dataType) ||
(cp.items != null && "os.File".equals(cp.items.dataType)))) {
if (!addedOSImport && ("*os.File".equals(cp.dataType) ||
(cp.items != null && "*os.File".equals(cp.items.dataType)))) {
imports.add(createMapping("import", "os"));
addedOSImport = true;
}
}
if (this instanceof GoClientCodegen && model.isEnum) {
imports.add(createMapping("import", "fmt"));
}
// if oneOf contains "time.Time" type
if (!addedTimeImport && model.oneOf != null && model.oneOf.contains("time.Time")) {
imports.add(createMapping("import", "time"));
}
// if oneOf contains "null" type
if (model.oneOf != null && !model.oneOf.isEmpty() && model.oneOf.contains("nil")) {
model.isNullable = true;

View File

@@ -1345,6 +1345,9 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
codegenModel.imports.add("JsonTypeInfo");
codegenModel.imports.add("JsonIgnoreProperties");
}
if (codegenModel.getIsClassnameSanitized() && additionalProperties.containsKey(JACKSON) && !codegenModel.isEnum) {
codegenModel.imports.add("JsonTypeName");
}
if (allDefinitions != null && codegenModel.parentSchema != null && codegenModel.hasEnums) {
final Schema parentModel = allDefinitions.get(codegenModel.parentSchema);
final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
@@ -1370,10 +1373,6 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
if (model.getIsClassnameSanitized() && additionalProperties.containsKey(JACKSON)) {
model.imports.add("JsonTypeName");
}
if (serializeBigDecimalAsString) {
if ("decimal".equals(property.baseType) || "bigdecimal".equalsIgnoreCase(property.baseType)) {
// we serialize BigDecimal as `string` to avoid precision loss

View File

@@ -63,6 +63,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
protected String shardAuthorEmail = "";
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
protected List<String> primitiveTypes = new ArrayList<String>();
public static final String SHARD_NAME = "shardName";
public static final String MODULE_NAME = "moduleName";
@@ -184,6 +185,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
instantiationTypes.put("map", "Hash");
instantiationTypes.put("array", "Array");
instantiationTypes.put("set", "Set");
primitiveTypes = new ArrayList<String>(typeMapping.values());
// remove modelPackage and apiPackage added by default
cliOptions.removeIf(opt -> CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) ||
@@ -355,6 +357,15 @@ public class CrystalClientCodegen extends DefaultCodegen {
return toModelName(type);
}
@Override
public String toModelImport(String name) {
if (primitiveTypes.contains(name)) {
return null;
} else {
return toModelFilename(name);
}
}
@Override
public String toModelName(final String name) {
String modelName;

View File

@@ -88,6 +88,9 @@ public class ElixirClientCodegen extends DefaultCodegen {
.includeClientModificationFeatures(
ClientModificationFeature.BasePath
)
.includeDataTypeFeatures(
DataTypeFeature.AnyType
)
);
// set the output folder here
@@ -188,10 +191,12 @@ public class ElixirClientCodegen extends DefaultCodegen {
"List",
"Atom",
"Map",
"AnyType",
"Tuple",
"PID",
"DateTime",
"map()" // This is a workaround, since the DefaultCodeGen uses our elixir TypeSpec datetype to evaluate the primitive
"map()", // This is a workaround, since the DefaultCodeGen uses our elixir TypeSpec datetype to evaluate the primitive
"any()"
)
);
@@ -575,6 +580,8 @@ public class ElixirClientCodegen extends DefaultCodegen {
return "String.t";
} else if (ModelUtils.isStringSchema(p)) {
return "String.t";
} else if (p.getType() == null) {
return "any()";
}
return super.getTypeDeclaration(p);
}
@@ -785,8 +792,13 @@ public class ElixirClientCodegen extends DefaultCodegen {
returnEntry.append(moduleName);
returnEntry.append(".Model.");
}
returnEntry.append(exResponse.baseType);
returnEntry.append(".t");
if (exResponse.baseType.equals("AnyType")) {
returnEntry.append("any()");
}else {
returnEntry.append(exResponse.baseType);
returnEntry.append(".t");
}
} else {
if (exResponse.containerType.equals("array") ||
exResponse.containerType.equals("set")) {
@@ -795,8 +807,13 @@ public class ElixirClientCodegen extends DefaultCodegen {
returnEntry.append(moduleName);
returnEntry.append(".Model.");
}
returnEntry.append(exResponse.baseType);
returnEntry.append(".t)");
if (exResponse.baseType.equals("AnyType")) {
returnEntry.append("any())");
}else {
returnEntry.append(exResponse.baseType);
returnEntry.append(".t)");
}
} else if (exResponse.containerType.equals("map")) {
returnEntry.append("map()");
}

View File

@@ -305,7 +305,7 @@ public class GoServerCodegen extends AbstractGoCodegen {
for (CodegenOperation operation : operations) {
for (CodegenParameter param : operation.allParams) {
// import "os" if the operation uses files
if (!addedOSImport && ("os.File".equals(param.dataType) || ("[]os.File".equals(param.dataType)))) {
if (!addedOSImport && ("*os.File".equals(param.dataType) || ("[]*os.File".equals(param.dataType)))) {
imports.add(createMapping("import", "os"));
addedOSImport = true;
}

View File

@@ -43,6 +43,8 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen
*/
protected static final String JAXRS_TEMPLATE_DIRECTORY_NAME = "JavaJaxRS";
public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles";
protected boolean useBeanValidation = false;
protected boolean useGenericResponse = false;
@@ -53,6 +55,8 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen
private boolean useJackson = false;
protected boolean useAbstractionForFiles = false;
public JavaCXFClientCodegen() {
super();
@@ -90,6 +94,7 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen
cliOptions.add(CliOption.newBoolean(USE_GZIP_FEATURE_FOR_TESTS, "Use Gzip Feature for tests"));
cliOptions.add(CliOption.newBoolean(USE_LOGGING_FEATURE_FOR_TESTS, "Use Logging Feature for tests"));
cliOptions.add(CliOption.newBoolean(USE_GENERIC_RESPONSE, "Use generic response"));
cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk."));
}
@Override
@@ -116,6 +121,10 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen
useJackson = convertPropertyToBooleanAndWriteBack(JACKSON);
}
if (additionalProperties.containsKey(USE_ABSTRACTION_FOR_FILES)) {
this.setUseAbstractionForFiles(convertPropertyToBooleanAndWriteBack(USE_ABSTRACTION_FOR_FILES));
}
supportingFiles.clear(); // Don't need extra files provided by AbstractJAX-RS & Java Codegen
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")
@@ -218,4 +227,8 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen
public boolean isUseJackson() {
return useJackson;
}
public void setUseAbstractionForFiles(boolean useAbstractionForFiles) {
this.useAbstractionForFiles = useAbstractionForFiles;
}
}

View File

@@ -36,6 +36,8 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen
implements CXFServerFeatures, GzipTestFeatures, LoggingTestFeatures, UseGenericResponseFeatures {
private final Logger LOGGER = LoggerFactory.getLogger(JavaCXFServerCodegen.class);
public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles";
protected boolean addConsumesProducesJson = true;
protected boolean generateSpringApplication = false;
@@ -70,6 +72,8 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen
protected boolean useGenericResponse = false;
protected boolean useAbstractionForFiles = false;
public JavaCXFServerCodegen() {
super();
@@ -126,6 +130,7 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen
cliOptions.add(CliOption.newBoolean(GENERATE_NON_SPRING_APPLICATION, "Generate non-Spring application"));
cliOptions.add(CliOption.newBoolean(USE_GENERIC_RESPONSE, "Use generic response"));
cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk."));
}
@@ -184,6 +189,10 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen
this.setGenerateNonSpringApplication(generateNonSpringApplication);
}
if (additionalProperties.containsKey(USE_ABSTRACTION_FOR_FILES)) {
this.setUseAbstractionForFiles(convertPropertyToBooleanAndWriteBack(USE_ABSTRACTION_FOR_FILES));
}
supportingFiles.clear(); // Don't need extra files provided by AbstractJAX-RS & Java Codegen
supportingFiles.add(new SupportingFile("server/pom.mustache", "", "pom.xml")
@@ -332,6 +341,10 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen
this.useGenericResponse = useGenericResponse;
}
public void setUseAbstractionForFiles(boolean useAbstractionForFiles) {
this.useAbstractionForFiles = useAbstractionForFiles;
}
@Override
protected void updateModelForObject(CodegenModel m, Schema schema) {
/**

View File

@@ -68,6 +68,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles";
public static final String DYNAMIC_OPERATIONS = "dynamicOperations";
public static final String SUPPORT_STREAMING = "supportStreaming";
public static final String SUPPORT_URL_QUERY = "supportUrlQuery";
public static final String GRADLE_PROPERTIES = "gradleProperties";
public static final String ERROR_OBJECT_TYPE = "errorObjectType";
@@ -119,6 +120,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
protected boolean useAbstractionForFiles = false;
protected boolean dynamicOperations = false;
protected boolean supportStreaming = false;
protected boolean withAWSV4Signature = false;
protected String gradleProperties;
protected String errorObjectType;
protected String authFolder;
@@ -192,7 +194,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations"));
cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION, "Perform BeanValidation"));
cliOptions.add(CliOption.newBoolean(USE_GZIP_FEATURE, "Send gzip-encoded requests"));
cliOptions.add(CliOption.newBoolean(USE_RUNTIME_EXCEPTION, "Use RuntimeException instead of Exception"));
cliOptions.add(CliOption.newBoolean(USE_RUNTIME_EXCEPTION, "Use RuntimeException instead of Exception. Only jersey, jersey2, jersey3, okhttp-gson, vertx, microprofile support this option."));
cliOptions.add(CliOption.newBoolean(ASYNC_NATIVE, "If true, async handlers will be used, instead of the sync version"));
cliOptions.add(CliOption.newBoolean(USE_REFLECTION_EQUALS_HASHCODE, "Use org.apache.commons.lang3.builder for equals and hashCode in the models. WARNING: This will fail under a security manager, unless the appropriate permissions are set up correctly and also there's potential performance impact."));
cliOptions.add(CliOption.newBoolean(CASE_INSENSITIVE_RESPONSE_HEADERS, "Make API response's headers case-insensitive. Available on " + OKHTTP_GSON + ", " + JERSEY2 + " libraries"));
@@ -200,6 +202,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk. Available on resttemplate, webclient, libraries"));
cliOptions.add(CliOption.newBoolean(DYNAMIC_OPERATIONS, "Generate operations dynamically at runtime from an OAS", this.dynamicOperations));
cliOptions.add(CliOption.newBoolean(SUPPORT_STREAMING, "Support streaming endpoint (beta)", this.supportStreaming));
cliOptions.add(CliOption.newBoolean(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT, CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT_DESC + " (only available for okhttp-gson library)", this.withAWSV4Signature));
cliOptions.add(CliOption.newString(GRADLE_PROPERTIES, "Append additional Gradle properties to the gradle.properties file"));
cliOptions.add(CliOption.newString(ERROR_OBJECT_TYPE, "Error Object type. (This option is for okhttp-gson-next-gen only)"));
cliOptions.add(CliOption.newString(CONFIG_KEY, "Config key in @RegisterRestClient. Default to none. Only `microprofile` supports this option."));
@@ -407,6 +410,11 @@ public class JavaClientCodegen extends AbstractJavaCodegen
}
additionalProperties.put(SUPPORT_STREAMING, supportStreaming);
if (additionalProperties.containsKey(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT)) {
this.setWithAWSV4Signature(Boolean.parseBoolean(additionalProperties.get(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT).toString()));
}
additionalProperties.put(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT, withAWSV4Signature);
if (additionalProperties.containsKey(GRADLE_PROPERTIES)) {
this.setGradleProperties(additionalProperties.get(GRADLE_PROPERTIES).toString());
}
@@ -420,6 +428,16 @@ public class JavaClientCodegen extends AbstractJavaCodegen
this.webclientBlockingOperations = Boolean.parseBoolean(additionalProperties.get(WEBCLIENT_BLOCKING_OPERATIONS).toString());
}
// add URL query deepObject support to native, apache-httpclient by default
if (!additionalProperties.containsKey(SUPPORT_URL_QUERY)) {
if (isLibrary(NATIVE) || isLibrary(APACHE)) {
// default to true for native and apache-httpclient
additionalProperties.put(SUPPORT_URL_QUERY, true);
}
} else {
additionalProperties.put(SUPPORT_URL_QUERY, Boolean.parseBoolean(additionalProperties.get(SUPPORT_URL_QUERY).toString()));
}
final String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");
final String apiFolder = (sourceFolder + '/' + apiPackage).replace(".", "/");
final String modelsFolder = (sourceFolder + File.separator + modelPackage().replace('.', File.separatorChar)).replace('/', File.separatorChar);
@@ -459,6 +477,9 @@ public class JavaClientCodegen extends AbstractJavaCodegen
supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java"));
supportingFiles.add(new SupportingFile("auth/HttpBearerAuth.mustache", authFolder, "HttpBearerAuth.java"));
supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java"));
if (OKHTTP_GSON.equals(getLibrary()) && withAWSV4Signature) {
supportingFiles.add(new SupportingFile("auth/AWS4Auth.mustache", authFolder, "AWS4Auth.java"));
}
}
supportingFiles.add(new SupportingFile("gradlew.mustache", "", "gradlew"));
@@ -1146,6 +1167,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen
this.supportStreaming = supportStreaming;
}
public void setWithAWSV4Signature(boolean withAWSV4Signature) {
this.withAWSV4Signature = withAWSV4Signature;
}
public void setGradleProperties(final String gradleProperties) {
this.gradleProperties = gradleProperties;
}

View File

@@ -79,6 +79,8 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
protected boolean renderJavadoc = true;
protected boolean removeOAuthSecurities = true;
Map<String, ModelsMap> enumRefs = new HashMap<>();
public ScalaSttpClientCodegen() {
super();
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
@@ -261,14 +263,8 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
@SuppressWarnings("unchecked")
private void postProcessUpdateImports(final Map<String, ModelsMap> models) {
final String prefix = modelPackage() + ".";
Map<String, ModelsMap> enumRefs = new HashMap<>();
for (String key : models.keySet()) {
CodegenModel model = ModelUtils.getModelByName(key, models);
if (model.isEnum) {
ModelsMap objs = models.get(key);
enumRefs.put(key, objs);
}
}
enumRefs = getEnumRefs(models);
for (String openAPIName : models.keySet()) {
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
@@ -276,6 +272,7 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
LOGGER.warn("Expected to retrieve model {} by name, but no model was found. Check your -Dmodels inclusions.", openAPIName);
continue;
}
ModelsMap objs = models.get(openAPIName);
List<Map<String, String>> imports = objs.getImports();
if (imports == null || imports.isEmpty()) {
@@ -285,25 +282,35 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
Iterator<Map<String, String>> iterator = imports.iterator();
while (iterator.hasNext()) {
String importPath = iterator.next().get("import");
Map<String, String> item = new HashMap<>();
if (importPath.startsWith(prefix)) {
if (isEnumClass(importPath, enumRefs)) {
Map<String, String> item = new HashMap<>();
item.put("import", importPath.concat("._"));
newImports.add(item);
}
}
else {
Map<String, String> item = new HashMap<>();
item.put("import", importPath);
newImports.add(item);
}
if (isEnumClass(importPath, enumRefs)) {
item.put("import", importPath.concat("._"));
newImports.add(item);
}
}
else {
item.put("import", importPath);
newImports.add(item);
}
}
// reset imports
objs.setImports(newImports);
}
}
private Map<String, ModelsMap> getEnumRefs(final Map<String, ModelsMap> models) {
Map<String, ModelsMap> enums = new HashMap<>();
for (String key : models.keySet()) {
CodegenModel model = ModelUtils.getModelByName(key, models);
if (model.isEnum) {
ModelsMap objs = models.get(key);
enums.put(key, objs);
}
}
return enums;
}
private boolean isEnumClass(final String importPath, final Map<String, ModelsMap> enumModels) {
if (enumModels == null || enumModels.isEmpty()) {
return false;
@@ -351,6 +358,26 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
LOGGER.error("Unable to find operations List", e);
}
}
// update imports for enum class
List<Map<String, String>> newImports = new ArrayList<>();
List<Map<String, String>> imports = objs.getImports();
if (imports != null && !imports.isEmpty()) {
Iterator<Map<String, String>> iterator = imports.iterator();
while (iterator.hasNext()) {
String importPath = iterator.next().get("import");
Map<String, String> item = new HashMap<>();
if (isEnumClass(importPath, enumRefs)) {
item.put("import", importPath.concat("._"));
}
else {
item.put("import", importPath);
}
newImports.add(item);
}
}
objs.setImports(newImports);
return super.postProcessOperationsWithModels(objs, allModels);
}

View File

@@ -241,7 +241,7 @@ public class SpringCodegen extends AbstractJavaCodegen
"Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies",
useSwaggerUI));
cliOptions.add(CliOption.newBoolean(USE_SPRING_BOOT3,
"Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports).",
"Generate code and provide dependencies for use with Spring Boot 3.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.",
useSpringBoot3));
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
@@ -473,6 +473,8 @@ public class SpringCodegen extends AbstractJavaCodegen
if (AnnotationLibrary.SWAGGER1.equals(getAnnotationLibrary())) {
throw new IllegalArgumentException(AnnotationLibrary.SWAGGER1.getPropertyName() + " is not supported with Spring Boot > 3.x");
}
useJakartaEe=true;
additionalProperties.put(USE_JAKARTA_EE, useJakartaEe);
applyJakartaPackage();
}
writePropertyBack(USE_SPRING_BOOT3, isUseSpringBoot3());
@@ -483,6 +485,9 @@ public class SpringCodegen extends AbstractJavaCodegen
importMapping.put("DateTimeFormat", "org.springframework.format.annotation.DateTimeFormat");
importMapping.put("ApiIgnore", "springfox.documentation.annotations.ApiIgnore");
importMapping.put("ParameterObject", "org.springdoc.api.annotations.ParameterObject");
if (isUseSpringBoot3()) {
importMapping.put("ParameterObject", "org.springdoc.core.annotations.ParameterObject");
}
if (useOptional) {
writePropertyBack(USE_OPTIONAL, useOptional);

View File

@@ -476,6 +476,43 @@ public class ModelUtils {
return false;
}
/**
* Return true if the specified schema is composed with more than one of the following:
* 'oneOf', 'anyOf' or 'allOf'.
*
* @param schema the OAS schema
* @return true if the specified schema is a Composed schema.
*/
public static boolean isComplexComposedSchema(Schema schema) {
if (!(schema instanceof ComposedSchema)) {
return false;
}
int count = 0;
if (schema.getAllOf() != null && !schema.getAllOf().isEmpty()) {
count++;
}
if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) {
count++;
}
if (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty()) {
count++;
}
if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
count++;
}
if (count > 1) {
return true;
}
return false;
}
/**
* Return true if the specified 'schema' is an object that can be extended with additional properties.
* Additional properties means a Schema should support all explicitly defined properties plus any

View File

@@ -893,9 +893,10 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
* @param path The sub path
* @param queryParams The query parameters
* @param collectionQueryParams The collection query parameters
* @param urlQueryDeepObject URL query string of the deep object parameters
* @return The full URL
*/
private String buildUrl(String path, List<Pair> queryParams, List<Pair> collectionQueryParams) {
private String buildUrl(String path, List<Pair> queryParams, List<Pair> collectionQueryParams, String urlQueryDeepObject) {
String baseURL;
if (serverIndex != null) {
if (serverIndex < 0 || serverIndex >= servers.size()) {
@@ -946,6 +947,11 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
}
}
if (urlQueryDeepObject != null && urlQueryDeepObject.length() > 0) {
url.append(url.toString().contains("?") ? "&" : "?");
url.append(urlQueryDeepObject);
}
return url.toString();
}
@@ -987,6 +993,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
* @param method The request method, one of "GET", "POST", "PUT", and "DELETE"
* @param queryParams The query parameters
* @param collectionQueryParams The collection query parameters
* @param urlQueryDeepObject A URL query string for deep object parameters
* @param body The request body object - if it is not binary, otherwise null
* @param headerParams The header parameters
* @param cookieParams The cookie parameters
@@ -1003,6 +1010,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
String method,
List<Pair> queryParams,
List<Pair> collectionQueryParams,
String urlQueryDeepObject,
Object body,
Map<String, String> headerParams,
Map<String, String> cookieParams,
@@ -1016,7 +1024,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
}
updateParamsForAuth(authNames, queryParams, headerParams, cookieParams);
final String url = buildUrl(path, queryParams, collectionQueryParams);
final String url = buildUrl(path, queryParams, collectionQueryParams, urlQueryDeepObject);
RequestBuilder builder = RequestBuilder.create(method);
builder.setUri(url);

View File

@@ -18,6 +18,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
{{/fullJavaUtil}}
{{>generatedAnnotation}}
@@ -75,7 +76,8 @@ public class {{classname}} {
String localVarPath = "{{{path}}}"{{#pathParams}}
.replaceAll("\\{" + "{{baseName}}" + "\\}", apiClient.escapeString({{{paramName}}}.toString())){{/pathParams}};
// query params
{{javaUtilPrefix}}StringJoiner localVarQueryStringJoiner = new StringJoiner("&");
String localVarQueryParameterBaseName;
{{javaUtilPrefix}}List<Pair> localVarQueryParams = new {{javaUtilPrefix}}ArrayList<Pair>();
{{javaUtilPrefix}}List<Pair> localVarCollectionQueryParams = new {{javaUtilPrefix}}ArrayList<Pair>();
{{javaUtilPrefix}}Map<String, String> localVarHeaderParams = new {{javaUtilPrefix}}HashMap<String, String>();
@@ -84,7 +86,15 @@ public class {{classname}} {
{{#queryParams}}
{{#isDeepObject}}
{{#collectionFormat}}localVarCollectionQueryParams.addAll(apiClient.parameterToPairs("{{{collectionFormat}}}", {{/collectionFormat}}{{^collectionFormat}}localVarQueryParams.addAll(apiClient.parameterToPair({{/collectionFormat}}"{{baseName}}", {{paramName}}));
localVarQueryParameterBaseName = "{{{baseName}}}";
{{#isArray}}
for (int i=0; i < {{paramName}}.size(); i++) {
localVarQueryStringJoiner.add({{paramName}}.get(i).toUrlQueryString(String.format("{{baseName}}[%d]", i)));
}
{{/isArray}}
{{^isArray}}
localVarQueryStringJoiner.add({{paramName}}.toUrlQueryString("{{baseName}}"));
{{/isArray}}
{{/isDeepObject}}
{{^isDeepObject}}
{{#isExplode}}
@@ -99,7 +109,12 @@ public class {{classname}} {
{{/vars}}
{{/hasVars}}
{{^hasVars}}
{{#isModel}}
localVarQueryStringJoiner.add({{paramName}}.toUrlQueryString());
{{/isModel}}
{{^isModel}}
{{#collectionFormat}}localVarCollectionQueryParams.addAll(apiClient.parameterToPairs("{{{collectionFormat}}}", {{/collectionFormat}}{{^collectionFormat}}localVarQueryParams.addAll(apiClient.parameterToPair({{/collectionFormat}}"{{baseName}}", {{paramName}}));
{{/isModel}}
{{/hasVars}}
{{/isExplode}}
{{^isExplode}}
@@ -142,6 +157,7 @@ public class {{classname}} {
"{{httpMethod}}",
localVarQueryParams,
localVarCollectionQueryParams,
localVarQueryStringJoiner.toString(),
localVarPostBody,
localVarHeaderParams,
localVarCookieParams,

View File

@@ -3,7 +3,7 @@ package {{apiPackage}};
import {{rootJavaEEPackage}}.ws.rs.core.Response;
public class ApiException extends Exception {
public class ApiException extends{{#useRuntimeException}} RuntimeException {{/useRuntimeException}}{{^useRuntimeException}} Exception {{/useRuntimeException}}{
private static final long serialVersionUID = 1L;
private Response response;

View File

@@ -338,7 +338,7 @@ public class {{classname}} {
{{#hasQueryParams}}
{{javaUtilPrefix}}List<Pair> localVarQueryParams = new {{javaUtilPrefix}}ArrayList<>();
StringJoiner localVarQueryDeepObjectStringJoiner = new StringJoiner("&");
{{javaUtilPrefix}}StringJoiner localVarQueryStringJoiner = new {{javaUtilPrefix}}StringJoiner("&");
String localVarQueryParameterBaseName;
{{#queryParams}}
localVarQueryParameterBaseName = "{{{baseName}}}";
@@ -350,11 +350,11 @@ public class {{classname}} {
if ({{paramName}} != null) {
{{#isArray}}
for (int i=0; i < {{paramName}}.size(); i++) {
localVarQueryDeepObjectStringJoiner.add({{paramName}}.get(i).toUrlQueryString(String.format("{{baseName}}[%d]", i)));
localVarQueryStringJoiner.add({{paramName}}.get(i).toUrlQueryString(String.format("{{baseName}}[%d]", i)));
}
{{/isArray}}
{{^isArray}}
localVarQueryDeepObjectStringJoiner.add({{paramName}}.toUrlQueryString("{{baseName}}"));
localVarQueryStringJoiner.add({{paramName}}.toUrlQueryString("{{baseName}}"));
{{/isArray}}
}
{{/isDeepObject}}
@@ -371,7 +371,12 @@ public class {{classname}} {
{{/vars}}
{{/hasVars}}
{{^hasVars}}
{{#isModel}}
localVarQueryStringJoiner.add({{paramName}}.toUrlQueryString());
{{/isModel}}
{{^isModel}}
localVarQueryParams.addAll(ApiClient.parameterToPairs("{{baseName}}", {{paramName}}));
{{/isModel}}
{{/hasVars}}
{{/isExplode}}
{{^isExplode}}
@@ -381,11 +386,11 @@ public class {{classname}} {
{{/collectionFormat}}
{{/queryParams}}
if (!localVarQueryParams.isEmpty() || localVarQueryDeepObjectStringJoiner.length() != 0) {
if (!localVarQueryParams.isEmpty() || localVarQueryStringJoiner.length() != 0) {
{{javaUtilPrefix}}StringJoiner queryJoiner = new {{javaUtilPrefix}}StringJoiner("&");
localVarQueryParams.forEach(p -> queryJoiner.add(p.getName() + '=' + p.getValue()));
if (localVarQueryDeepObjectStringJoiner.length() != 0) {
queryJoiner.add(localVarQueryDeepObjectStringJoiner.toString());
if (localVarQueryStringJoiner.length() != 0) {
queryJoiner.add(localVarQueryStringJoiner.toString());
}
localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath + '?' + queryJoiner.toString()));
} else {

View File

@@ -16,13 +16,15 @@ import com.fasterxml.jackson.annotation.JsonAnySetter;
{{/additionalPropertiesType}}
{{/model}}
{{/models}}
{{#supportUrlQuery}}
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.StringJoiner;
{{/supportUrlQuery}}
import java.util.Objects;
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.StringJoiner;
{{#imports}}
import {{import}};
{{/imports}}

View File

@@ -62,6 +62,7 @@ import com.google.gson.stream.JsonWriter;
}
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}{{#enumUnknownDefaultCase}}{{#allowableValues}}{{#enumVars}}{{#-last}}return {{{name}}};{{/-last}}{{/enumVars}}{{/allowableValues}}{{/enumUnknownDefaultCase}}{{^enumUnknownDefaultCase}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/enumUnknownDefaultCase}}{{/isNullable}}
}
{{#supportUrlQuery}}
/**
* Convert the instance into URL query string.
@@ -76,6 +77,7 @@ import com.google.gson.stream.JsonWriter;
return String.format("%s=%s", prefix, this.toString());
}
{{/supportUrlQuery}}
{{#gson}}

View File

@@ -228,4 +228,166 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
}
{{/oneOf}}
{{#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("&");
{{#composedSchemas.oneOf}}
if (getActualInstance() instanceof {{{dataType}}}) {
{{#isArray}}
{{#items.isPrimitiveType}}
{{#uniqueItems}}
if (getActualInstance() != null) {
int i = 0;
for ({{items.dataType}} _item : ({{{dataType}}})getActualInstance()) {
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), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
i++;
}
{{/uniqueItems}}
{{^uniqueItems}}
if (getActualInstance() != null) {
for (int i = 0; i < (({{{dataType}}})getActualInstance()).size(); i++) {
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(getActualInstance().get(i)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
}
{{/uniqueItems}}
{{/items.isPrimitiveType}}
{{^items.isPrimitiveType}}
{{#items.isModel}}
{{#uniqueItems}}
if (getActualInstance() != null) {
int i = 0;
for ({{items.dataType}} _item : ({{{dataType}}})getActualInstance()) {
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 (getActualInstance() != null) {
for (int i = 0; i < (({{{dataType}}})getActualInstance()).size(); i++) {
if ((({{{dataType}}})getActualInstance()).get(i) != null) {
joiner.add((({{{items.dataType}}})getActualInstance()).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 (getActualInstance() != null) {
int i = 0;
for ({{items.dataType}} _item : ({{{dataType}}})getActualInstance()) {
if (_item != null) {
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), StandardCharsets.UTF_8).replaceAll("\\+", "%20"));
}
i++;
}
}
{{/uniqueItems}}
{{^uniqueItems}}
if (getActualInstance() != null) {
for (int i = 0; i < (({{{dataType}}})getActualInstance()).size(); i++) {
if (getActualInstance().get(i) != null) {
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((({{{dataType}}})getActualInstance()).get(i)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
}
}
{{/uniqueItems}}
{{/items.isModel}}
{{/items.isPrimitiveType}}
{{/isArray}}
{{^isArray}}
{{#isMap}}
{{#items.isPrimitiveType}}
if (getActualInstance() != null) {
for (String _key : (({{{dataType}}})getActualInstance()).keySet()) {
joiner.add(String.format("%s{{baseName}}%s%s=%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, _key, containerSuffix),
getActualInstance().get(_key), URLEncoder.encode(String.valueOf((({{{dataType}}})getActualInstance()).get(_key)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
}
{{/items.isPrimitiveType}}
{{^items.isPrimitiveType}}
if (getActualInstance() != null) {
for (String _key : (({{{dataType}}})getActualInstance()).keySet()) {
if ((({{{dataType}}})getActualInstance()).get(_key) != null) {
joiner.add((({{{items.dataType}}})getActualInstance()).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 (getActualInstance() != null) {
joiner.add(String.format("%s{{{baseName}}}%s=%s", prefix, suffix, URLEncoder.encode(String.valueOf(getActualInstance()), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isModel}}
if (getActualInstance() != null) {
joiner.add((({{{dataType}}})getActualInstance()).toUrlQueryString(prefix + "{{{baseName}}}" + suffix));
}
{{/isModel}}
{{^isModel}}
if (getActualInstance() != null) {
joiner.add(String.format("%s{{{baseName}}}%s=%s", prefix, suffix, URLEncoder.encode(String.valueOf(getActualInstance()), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
{{/isModel}}
{{/isPrimitiveType}}
{{/isMap}}
{{/isArray}}
return joiner.toString();
}
{{/composedSchemas.oneOf}}
return null;
}
{{/supportUrlQuery}}
}

View File

@@ -348,7 +348,16 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
}
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.
@@ -357,8 +366,18 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
* @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("&");
@@ -371,7 +390,9 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
if ({{getter}}() != null) {
int i = 0;
for ({{items.dataType}} _item : {{getter}}()) {
joiner.add(String.format("%s[{{baseName}}][%d]=%s", prefix, i, URLEncoder.encode(String.valueOf(_item), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
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), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
i++;
}
@@ -379,7 +400,9 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
{{^uniqueItems}}
if ({{getter}}() != null) {
for (int i = 0; i < {{getter}}().size(); i++) {
joiner.add(String.format("%s[{{baseName}}][%d]=%s", prefix, i, URLEncoder.encode(String.valueOf({{getter}}().get(i)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
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)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
}
{{/uniqueItems}}
@@ -390,8 +413,9 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
if ({{getter}}() != null) {
int i = 0;
for ({{items.dataType}} _item : {{getter}}()) {
if ({{getter}}().get(i) != null) {
joiner.add(_item.toUrlQueryString(String.format("%s[{{baseName}}][%d]", prefix, i)));
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++;
@@ -401,7 +425,8 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
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}}][%d]", prefix, i)));
joiner.add({{getter}}().get(i).toUrlQueryString(String.format("%s{{baseName}}%s%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, i, containerSuffix))));
}
}
}
@@ -413,7 +438,9 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
int i = 0;
for ({{items.dataType}} _item : {{getter}}()) {
if (_item != null) {
joiner.add(String.format("%s[{{baseName}}][%d]=%s", prefix, i, URLEncoder.encode(String.valueOf(_item), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
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), StandardCharsets.UTF_8).replaceAll("\\+", "%20"));
}
i++;
}
@@ -423,7 +450,9 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
if ({{getter}}() != null) {
for (int i = 0; i < {{getter}}().size(); i++) {
if ({{getter}}().get(i) != null) {
joiner.add(String.format("%s[{{baseName}}][%d]=%s", prefix, i, URLEncoder.encode(String.valueOf({{getter}}().get(i)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
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)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
}
}
@@ -436,7 +465,9 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
{{#items.isPrimitiveType}}
if ({{getter}}() != null) {
for (String _key : {{getter}}().keySet()) {
joiner.add(String.format("%s[{{baseName}}][%s]=%s", prefix, {{getter}}().get(_key), URLEncoder.encode(String.valueOf({{getter}}().get(_key)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
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)), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
}
{{/items.isPrimitiveType}}
@@ -444,7 +475,8 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
if ({{getter}}() != null) {
for (String _key : {{getter}}().keySet()) {
if ({{getter}}().get(_key) != null) {
joiner.add({{getter}}().get(_key).toUrlQueryString(String.format("%s[{{baseName}}][%s]", prefix, _key)));
joiner.add({{getter}}().get(_key).toUrlQueryString(String.format("%s{{baseName}}%s%s", prefix, suffix,
"".equals(suffix) ? "" : String.format("%s%d%s", containerPrefix, _key, containerSuffix))));
}
}
}
@@ -453,18 +485,18 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
{{^isMap}}
{{#isPrimitiveType}}
if ({{getter}}() != null) {
joiner.add(String.format("%s[{{{baseName}}}]=%s", prefix, URLEncoder.encode(String.valueOf({{{getter}}}()), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
joiner.add(String.format("%s{{{baseName}}}%s=%s", prefix, suffix, URLEncoder.encode(String.valueOf({{{getter}}}()), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isModel}}
if ({{getter}}() != null) {
joiner.add({{getter}}().toUrlQueryString(prefix + "[{{{baseName}}}]"));
joiner.add({{getter}}().toUrlQueryString(prefix + "{{{baseName}}}" + suffix));
}
{{/isModel}}
{{^isModel}}
if ({{getter}}() != null) {
joiner.add(String.format("%s[{{{baseName}}}]=%s", prefix, URLEncoder.encode(String.valueOf({{{getter}}}()), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
joiner.add(String.format("%s{{{baseName}}}%s=%s", prefix, suffix, URLEncoder.encode(String.valueOf({{{getter}}}()), StandardCharsets.UTF_8).replaceAll("\\+", "%20")));
}
{{/isModel}}
{{/isPrimitiveType}}
@@ -474,6 +506,7 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
{{/allVars}}
return joiner.toString();
}
{{/supportUrlQuery}}
{{#parcelableModel}}
public void writeToParcel(Parcel out, int flags) {

View File

@@ -65,6 +65,9 @@ import {{invokerPackage}}.auth.OAuth;
import {{invokerPackage}}.auth.RetryingOAuth;
import {{invokerPackage}}.auth.OAuthFlow;
{{/hasOAuthMethods}}
{{#withAWSV4Signature}}
import {{invokerPackage}}.auth.AWS4Auth;
{{/withAWSV4Signature}}
/**
* <p>ApiClient class.</p>
@@ -135,7 +138,8 @@ public class ApiClient {
authentications.put("{{name}}", new HttpBasicAuth());{{/isBasicBasic}}{{^isBasicBasic}}
authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));{{/isBasicBasic}}{{/isBasic}}{{#isApiKey}}
authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInCookie}}"cookie"{{/isKeyInCookie}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}}
authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}
authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}{{#withAWSV4Signature}}
authentications.put("AWS4Auth", new AWS4Auth());{{/withAWSV4Signature}}
// Prevent the authentications from being modified.
authentications = Collections.unmodifiableMap(authentications);
}
@@ -154,7 +158,8 @@ public class ApiClient {
authentications.put("{{name}}", new HttpBasicAuth());{{/isBasicBasic}}{{^isBasicBasic}}
authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));{{/isBasicBasic}}{{/isBasic}}{{#isApiKey}}
authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInCookie}}"cookie"{{/isKeyInCookie}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}}
authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}
authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}{{#withAWSV4Signature}}
authentications.put("AWS4Auth", new AWS4Auth());{{/withAWSV4Signature}}
// Prevent the authentications from being modified.
authentications = Collections.unmodifiableMap(authentications);
}
@@ -225,7 +230,8 @@ public class ApiClient {
// Setup authentications (key: authentication name, value: authentication).{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
authentications.put("{{name}}", new HttpBasicAuth());{{/isBasicBasic}}{{^isBasicBasic}}
authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));{{/isBasicBasic}}{{/isBasic}}{{#isApiKey}}
authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInCookie}}"cookie"{{/isKeyInCookie}}, "{{keyParamName}}"));{{/isApiKey}}{{/authMethods}}
authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInCookie}}"cookie"{{/isKeyInCookie}}, "{{keyParamName}}"));{{/isApiKey}}{{/authMethods}}{{#withAWSV4Signature}}
authentications.put("AWS4Auth", new AWS4Auth());{{/withAWSV4Signature}}
// Prevent the authentications from being modified.
authentications = Collections.unmodifiableMap(authentications);
@@ -613,6 +619,28 @@ public class ApiClient {
throw new RuntimeException("No OAuth2 authentication configured!");
}
/**
* Helper method to set credentials for AWSV4 Signature
*
* @param accessKey Access Key
* @param secretKey Secret Key
* @param region Region
* @param service Service to access to
*/
public void setAWS4Configuration(String accessKey, String secretKey, String region, String service) {
{{#withAWSV4Signature}}
for (Authentication auth : authentications.values()) {
if (auth instanceof AWS4Auth) {
((AWS4Auth) auth).setCredentials(accessKey, secretKey);
((AWS4Auth) auth).setRegion(region);
((AWS4Auth) auth).setService(service);
return;
}
}
{{/withAWSV4Signature}}
throw new RuntimeException("No AWS4 authentication configured!");
}
/**
* Set the User-Agent header's value (by adding to the default header map).
*

View File

@@ -96,6 +96,10 @@ public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("{{{basePath}}}");
{{#withAWSV4Signature}}
// Configure AWS Signature V4 authorization
defaultClient.setAWS4Configuration("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY", "REGION", "SERVICE")
{{/withAWSV4Signature}}
{{#hasAuthMethods}}
{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
// Configure HTTP basic authorization: {{{name}}}

View File

@@ -212,7 +212,7 @@ public class {{classname}} {
localVarHeaderParams.put("Content-Type", localVarContentType);
}
String[] localVarAuthNames = new String[] { {{#authMethods}}"{{name}}"{{^-last}}, {{/-last}}{{/authMethods}} };
String[] localVarAuthNames = new String[] { {{#withAWSV4Signature}}"AWS4Auth"{{/withAWSV4Signature}}{{#authMethods}}{{#-first}}{{#withAWSV4Signature}}, {{/withAWSV4Signature}}{{/-first}}"{{name}}"{{^-last}}, {{/-last}}{{/authMethods}} };
return localVarApiClient.buildCall(basePath, localVarPath, {{^dynamicOperations}}"{{httpMethod}}"{{/dynamicOperations}}{{#dynamicOperations}}apiOperation.getMethod(){{/dynamicOperations}}, localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback);
}

View File

@@ -33,6 +33,10 @@ public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("{{{basePath}}}");
{{#withAWSV4Signature}}
// Configure AWS Signature V4 authorization
defaultClient.setAWS4Configuration("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY", "REGION", "SERVICE")
{{/withAWSV4Signature}}
{{#hasAuthMethods}}
{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
// Configure HTTP basic authorization: {{{name}}}

View File

@@ -0,0 +1,71 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import {{invokerPackage}}.ApiException;
import java.io.ByteArrayInputStream;
import java.net.URI;
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 okio.Buffer;
{{>generatedAnnotation}}
public class AWS4Auth implements Authentication {
private AWSCredentials credentials;
private String region;
private String service;
public AWS4Auth() {
this.credentials = new AnonymousAWSCredentials();
}
public void setCredentials(String accessKey, String secretKey) {
this.credentials = new BasicAWSCredentials(accessKey, secretKey);
}
public void setRegion(String region) {
this.region = region;
}
public void setService(String service) {
this.service = service;
}
@Override
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);
signableRequest.setContent(new ByteArrayInputStream(payload.getBytes()));
signableRequest.setHttpMethod(HttpMethodName.valueOf(method));
URI targetUri = null;
try {
targetUri = new URI(uri.getScheme(), "", uri.getHost(), uri.getPort(), "", "", "");
} catch (URISyntaxException e) {
return;
}
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());
}
}

View File

@@ -368,6 +368,14 @@
<version>${jackson-databind-nullable-version}</version>
</dependency>
{{/openApiNullable}}
{{#withAWSV4Signature}}
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-signer</artifactId>
<version>1.12.349</version>
</dependency>
{{/withAWSV4Signature}}
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>

View File

@@ -55,6 +55,11 @@ import {{javaxPackage}}.validation.Valid;
{{#performBeanValidation}}
import org.hibernate.validator.constraints.*;
{{/performBeanValidation}}
{{#supportUrlQuery}}
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.StringJoiner;
{{/supportUrlQuery}}
{{#models}}
{{#model}}

View File

@@ -78,6 +78,7 @@ import com.google.gson.stream.JsonWriter;
}
{{/gson}}
{{#jsonb}}
public static final class Deserializer implements JsonbDeserializer<{{datatypeWithEnum}}> {
@Override
public {{datatypeWithEnum}} deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
@@ -97,4 +98,20 @@ import com.google.gson.stream.JsonWriter;
}
}
{{/jsonb}}
{{#supportUrlQuery}}
/**
* Convert the instance into URL query string.
*
* @param prefix prefix of the query string
* @return URL query string
*/
public String toUrlQueryString(String prefix) {
if (prefix == null) {
prefix = "";
}
return String.format("%s=%s", prefix, this.toString());
}
{{/supportUrlQuery}}
}

View File

@@ -336,7 +336,200 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
}
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) {
@@ -396,4 +589,5 @@ public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtens
}
};
{{/parcelableModel}}
}

View File

@@ -69,7 +69,7 @@ public interface {{classname}} {
})
{{/implicitHeadersParams.0}}
@ApiResponses(value = { {{#responses}}
@ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, response = {{{baseType}}}.class{{#containerType}}, responseContainer = "{{{.}}}"{{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{^-last}},{{/-last}}{{/responses}} })
@ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, response = {{#isFile}}{{#useAbstractionForFiles}}InputStream{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{baseType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{baseType}}}{{/isFile}}.class{{#containerType}}, responseContainer = "{{{.}}}"{{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{^-last}},{{/-last}}{{/responses}} })
public {{>returnTypes}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}});
{{/operation}}
}

View File

@@ -113,7 +113,7 @@ public class {{classname}}Test {
@Test
public void {{operationId}}Test() {
{{#allParams}}
{{^isFile}}{{{dataType}}} {{paramName}} = null;{{/isFile}}{{#isFile}}org.apache.cxf.jaxrs.ext.multipart.Attachment {{paramName}} = null;{{/isFile}}
{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<InputStream>{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}} {{paramName}} = null;{{/isFile}}{{^isFile}}{{{dataType}}} {{paramName}} = null;{{/isFile}}
{{/allParams}}
//{{^vendorExtensions.x-java-is-response-void}}{{>returnTypes}} response = {{/vendorExtensions.x-java-is-response-void}}api.{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
{{^vendorExtensions.x-java-is-response-void}}//assertNotNull(response);{{/vendorExtensions.x-java-is-response-void}}

View File

@@ -1 +1 @@
{{#isBodyParam}}{{#useBeanValidation}}@Valid {{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{/isBodyParam}}
{{#isBodyParam}}{{#useBeanValidation}}@Valid {{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<InputStream>{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{/isBodyParam}}

View File

@@ -1 +1 @@
{{#isBodyParam}}{{{dataType}}} {{paramName}}{{/isBodyParam}}
{{#isBodyParam}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<InputStream>{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{/isBodyParam}}

View File

@@ -1,4 +1,4 @@
{{#useGenericResponse}}Response{{/useGenericResponse}}{{! non-generic response:
}}{{^useGenericResponse}}{{!
}}{{{returnType}}}{{!
}}{{#isResponseFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<InputStream>{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{returnType}}}{{/useAbstractionForFiles}}{{/isResponseFile}}{{^isResponseFile}}{{{returnType}}}{{/isResponseFile}}{{!
}}{{/useGenericResponse}}

View File

@@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
{{/swagger2AnnotationLibrary}}
{{#swagger1AnnotationLibrary}}
import io.swagger.annotations.*;
@@ -150,7 +151,7 @@ public interface {{classname}} {
{{/vendorExtensions.x-tags.size}}
responses = {
{{#responses}}
@ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{#baseType}}, content = {
@ApiResponse(responseCode = {{#isDefault}}"default"{{/isDefault}}{{^isDefault}}"{{{code}}}"{{/isDefault}}, description = "{{{message}}}"{{#baseType}}, content = {
{{#produces}}
@Content(mediaType = "{{{mediaType}}}", {{#isArray}}array = @ArraySchema({{/isArray}}schema = @Schema(implementation = {{{baseType}}}.class){{#isArray}}){{/isArray}}){{^-last}},{{/-last}}
{{/produces}}

View File

@@ -18,7 +18,7 @@ public class EnumConverterConfiguration {
{{#models}}
{{#model}}
{{#isEnum}}
@Bean
@Bean(name = "{{configPackage}}.EnumConverterConfiguration.{{classVarName}}Converter")
Converter<{{{dataType}}}, {{classname}}> {{classVarName}}Converter() {
return new Converter<{{{dataType}}}, {{classname}}>() {
@Override

View File

@@ -1 +1 @@
{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}} {{#isModel}}@RequestPart{{/isModel}}{{^isModel}}@RequestParam{{/isModel}}(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{{dataType}}} {{paramName}}{{/isFile}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#isArray}}List<{{/isArray}}{{#reactive}}Flux<Part>{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{#isArray}}>{{/isArray}} {{paramName}}{{/isFile}}{{/isFormParam}}
{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}} {{#isModel}}@RequestPart{{/isModel}}{{^isModel}}{{#isArray}}@RequestPart{{/isArray}}{{^isArray}}@RequestParam{{/isArray}}{{/isModel}}(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{{dataType}}} {{paramName}}{{/isFile}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#isArray}}List<{{/isArray}}{{#reactive}}Flux<Part>{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{#isArray}}>{{/isArray}} {{paramName}}{{/isFile}}{{/isFormParam}}

View File

@@ -8,9 +8,16 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;
@SpringBootApplication
@ComponentScan(basePackages = {"{{basePackage}}", "{{apiPackage}}" , "{{configPackage}}"})
@SpringBootApplication(
nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class
)
@ComponentScan(
basePackages = {"{{basePackage}}", "{{apiPackage}}" , "{{configPackage}}"},
nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class
)
public class OpenApiGeneratorApplication {
public static void main(String[] args) {
@@ -18,7 +25,7 @@ public class OpenApiGeneratorApplication {
}
{{#openApiNullable}}
@Bean
@Bean(name = "{{basePackage}}.OpenApiGeneratorApplication.jsonNullableModule")
public Module jsonNullableModule() {
return new JsonNullableModule();
}

View File

@@ -15,7 +15,7 @@
{{/springDocDocumentationProvider}}
{{^springDocDocumentationProvider}}
{{#swagger2AnnotationLibrary}}
<swagger-annotations.version>}2.2.0</swagger-annotations.version>
<swagger-annotations.version>}2.2.7</swagger-annotations.version>
{{/swagger2AnnotationLibrary}}
{{/springDocDocumentationProvider}}
{{#useSwaggerUI}}

View File

@@ -22,7 +22,7 @@
<swagger-annotations.version>1.6.6</swagger-annotations.version>
{{/swagger1AnnotationLibrary}}
{{#swagger2AnnotationLibrary}}
<swagger-annotations.version>}2.1.13</swagger-annotations.version>
<swagger-annotations.version>}2.2.7</swagger-annotations.version>
{{/swagger2AnnotationLibrary}}
{{/springDocDocumentationProvider}}
{{/springFoxDocumentationProvider}}

View File

@@ -15,7 +15,7 @@
{{/springDocDocumentationProvider}}
{{^springDocDocumentationProvider}}
{{#swagger2AnnotationLibrary}}
<swagger-annotations.version>}2.2.0</swagger-annotations.version>
<swagger-annotations.version>}2.2.7</swagger-annotations.version>
{{/swagger2AnnotationLibrary}}
{{/springDocDocumentationProvider}}
</properties>

View File

@@ -22,7 +22,7 @@
<swagger-annotations.version>1.6.6</swagger-annotations.version>
{{/swagger1AnnotationLibrary}}
{{#swagger2AnnotationLibrary}}
<swagger-annotations.version>}2.1.13</swagger-annotations.version>
<swagger-annotations.version>}2.2.7</swagger-annotations.version>
{{/swagger2AnnotationLibrary}}
{{/springDocDocumentationProvider}}
{{/springFoxDocumentationProvider}}

View File

@@ -1 +1 @@
{{#swagger2AnnotationLibrary}}@Parameter(name = "{{{baseName}}}", description = "{{{description}}}"{{#required}}, required = true{{/required}}){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/swagger1AnnotationLibrary}}
{{#swagger2AnnotationLibrary}}@Parameter(name = "{{{baseName}}}", description = "{{{description}}}"{{#required}}, required = true{{/required}}{{#isPathParam}}, in = ParameterIn.PATH{{/isPathParam}}{{#isQueryParam}}, in = ParameterIn.QUERY{{/isQueryParam}}{{#isCookieParam}}, in = ParameterIn.COOKIE{{/isCookieParam}}{{#isHeaderParam}}, in = ParameterIn.HEADER{{/isHeaderParam}}){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/swagger1AnnotationLibrary}}

View File

@@ -150,7 +150,7 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}}
{{#required}}@NotNull{{/required}}
{{/useBeanValidation}}
{{#swagger2AnnotationLibrary}}
@Schema(name = "{{{baseName}}}", {{#isReadOnly}}accessMode = Schema.AccessMode.READ_ONLY, {{/isReadOnly}}{{#example}}example = "{{{.}}}", {{/example}}{{#description}}description = "{{{.}}}", {{/description}}required = {{{required}}})
@Schema(name = "{{{baseName}}}"{{#isReadOnly}}, accessMode = Schema.AccessMode.READ_ONLY{{/isReadOnly}}{{#example}}, example = "{{{.}}}"{{/example}}{{#description}}, description = "{{{.}}}"{{/description}}, requiredMode = {{#required}}Schema.RequiredMode.REQUIRED{{/required}}{{^required}}Schema.RequiredMode.NOT_REQUIRED{{/required}})
{{/swagger2AnnotationLibrary}}
{{#swagger1AnnotationLibrary}}
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}")

View File

@@ -13,7 +13,7 @@ import io.swagger.v3.oas.models.security.SecurityScheme;
@Configuration
public class SpringDocConfiguration {
@Bean
@Bean(name = "{{configPackage}}.SpringDocConfiguration.apiInfo")
OpenAPI apiInfo() {
return new OpenAPI()
.info(

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
{{#operationResultTask}}
using System.Threading;
using System.Threading.Tasks;
{{/operationResultTask}}
using Microsoft.AspNetCore.Authorization;
@@ -31,7 +32,8 @@ namespace {{apiPackage}}
/// {{summary}}
/// </summary>{{#notes}}
/// <remarks>{{.}}</remarks>{{/notes}}{{#allParams}}
/// <param name="{{paramName}}">{{description}}{{#isDeprecated}} (deprecated){{/isDeprecated}}</param>{{/allParams}}{{#responses}}
/// <param name="{{paramName}}">{{description}}{{#isDeprecated}} (deprecated){{/isDeprecated}}</param>{{/allParams}}{{#operationResultTask}}{{#operationIsAsync}}
/// <param name="cancellationToken">The cancellation token to cancel the operation.</param>{{/operationIsAsync}}{{/operationResultTask}}{{#responses}}
/// <response code="{{code}}">{{message}}</response>{{/responses}}
[{{httpMethod}}]
[Route("{{{basePathWithoutHost}}}{{{path}}}")]
@@ -53,7 +55,7 @@ namespace {{apiPackage}}
{{#isDeprecated}}
[Obsolete]
{{/isDeprecated}}
public {{operationModifier}} {{#operationResultTask}}{{#operationIsAsync}}async {{/operationIsAsync}}Task<{{/operationResultTask}}IActionResult{{#operationResultTask}}>{{/operationResultTask}} {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{^-last}}{{^isCookieParam}}, {{/isCookieParam}}{{/-last}}{{/allParams}}){{^generateBody}};{{/generateBody}}
public {{operationModifier}} {{#operationResultTask}}{{#operationIsAsync}}async {{/operationIsAsync}}Task<{{/operationResultTask}}IActionResult{{#operationResultTask}}>{{/operationResultTask}} {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{^-last}}{{^isCookieParam}}, {{/isCookieParam}}{{/-last}}{{#-last}}{{#operationResultTask}}{{#operationIsAsync}}, {{/operationIsAsync}}{{/operationResultTask}}{{/-last}}{{/allParams}}{{#operationResultTask}}{{#operationIsAsync}}CancellationToken cancellationToken{{/operationIsAsync}}{{/operationResultTask}}){{^generateBody}};{{/generateBody}}
{{#generateBody}}
{
{{#cookieParams}}
@@ -78,7 +80,7 @@ namespace {{apiPackage}}
{{#isListCollection}}{{>listReturn}}{{/isListCollection}}{{^isListCollection}}{{#isMap}}{{>mapReturn}}{{/isMap}}{{^isMap}}{{>objectReturn}}{{/isMap}}{{/isListCollection}}
{{!TODO: defaultResponse, examples, auth, consumes, produces, nickname, externalDocs, imports, security}}
//TODO: Change the data returned
return {{#operationResultTask}}Task.FromResult<IActionResult>({{/operationResultTask}}new ObjectResult(example){{#operationResultTask}}){{/operationResultTask}};{{/returnType}}{{^returnType}}
return {{#operationResultTask}}{{#operationIsAsync}}await {{/operationIsAsync}}Task.FromResult<IActionResult>({{/operationResultTask}}new ObjectResult(example){{#operationResultTask}}){{/operationResultTask}};{{/returnType}}{{^returnType}}
throw new NotImplementedException();{{/returnType}}
}
{{/generateBody}}

View File

@@ -6,34 +6,34 @@
/// <summary>
/// A Json reader.
/// </summary>
/// <param name="reader"></param>
/// <param name="utf8JsonReader"></param>
/// <param name="typeToConvert"></param>
/// <param name="options"></param>
/// <param name="jsonSerializerOptions"></param>
/// <returns></returns>
/// <exception cref="JsonException"></exception>
public override {{classname}} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override {{classname}} Read(ref Utf8JsonReader utf8JsonReader, Type typeToConvert, JsonSerializerOptions jsonSerializerOptions)
{
int currentDepth = reader.CurrentDepth;
int currentDepth = utf8JsonReader.CurrentDepth;
if (reader.TokenType != JsonTokenType.StartObject && reader.TokenType != JsonTokenType.StartArray)
if (utf8JsonReader.TokenType != JsonTokenType.StartObject && utf8JsonReader.TokenType != JsonTokenType.StartArray)
throw new JsonException();
JsonTokenType startingTokenType = reader.TokenType;
JsonTokenType startingTokenType = utf8JsonReader.TokenType;
{{#composedSchemas.anyOf}}
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = reader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader, options, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = utf8JsonReader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader, jsonSerializerOptions, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});
{{/composedSchemas.anyOf}}
{{#composedSchemas.oneOf}}
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = reader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader, options, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = utf8JsonReader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader, jsonSerializerOptions, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});
{{/composedSchemas.oneOf}}
{{#composedSchemas.allOf}}
{{^isInherited}}
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = reader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref reader, options, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = utf8JsonReader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref utf8JsonReader, jsonSerializerOptions, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});
{{/isInherited}}
{{/composedSchemas.allOf}}
@@ -41,18 +41,18 @@
{{#isInnerEnum}}{{^isMap}}{{classname}}.{{/isMap}}{{/isInnerEnum}}{{{datatypeWithEnum}}}{{#isEnum}}{{#isNullable}}?{{/isNullable}}{{/isEnum}} {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = default;
{{/allVars}}
while (reader.Read())
while (utf8JsonReader.Read())
{
if (startingTokenType == JsonTokenType.StartObject && reader.TokenType == JsonTokenType.EndObject && currentDepth == reader.CurrentDepth)
if (startingTokenType == JsonTokenType.StartObject && utf8JsonReader.TokenType == JsonTokenType.EndObject && currentDepth == utf8JsonReader.CurrentDepth)
break;
if (startingTokenType == JsonTokenType.StartArray && reader.TokenType == JsonTokenType.EndArray && currentDepth == reader.CurrentDepth)
if (startingTokenType == JsonTokenType.StartArray && utf8JsonReader.TokenType == JsonTokenType.EndArray && currentDepth == utf8JsonReader.CurrentDepth)
break;
if (reader.TokenType == JsonTokenType.PropertyName && currentDepth == reader.CurrentDepth - 1)
if (utf8JsonReader.TokenType == JsonTokenType.PropertyName && currentDepth == utf8JsonReader.CurrentDepth - 1)
{
string{{nrt?}} propertyName = reader.GetString();
reader.Read();
string{{nrt?}} propertyName = utf8JsonReader.GetString();
utf8JsonReader.Read();
switch (propertyName)
{
@@ -62,38 +62,38 @@
{{^isMap}}
{{^isEnum}}
{{^isUuid}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetString();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetString();
{{/isUuid}}
{{/isEnum}}
{{/isMap}}
{{/isString}}
{{#isBoolean}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetBoolean();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetBoolean();
{{/isBoolean}}
{{#isNumeric}}
{{^isEnum}}
{{#isDouble}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetDouble();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetDouble();
{{/isDouble}}
{{#isDecimal}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetDecimal();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetDecimal();
{{/isDecimal}}
{{#isFloat}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = (float)reader.GetDouble();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = (float)utf8JsonReader.GetDouble();
{{/isFloat}}
{{#isLong}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetInt64();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetInt64();
{{/isLong}}
{{^isLong}}
{{^isFloat}}
{{^isDecimal}}
{{^isDouble}}
{{#isNullable}}
if (reader.TokenType != JsonTokenType.Null)
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetInt32();
if (utf8JsonReader.TokenType != JsonTokenType.Null)
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetInt32();
{{/isNullable}}
{{^isNullable}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetInt32();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetInt32();
{{/isNullable}}
{{/isDouble}}
{{/isDecimal}}
@@ -102,18 +102,18 @@
{{/isEnum}}
{{/isNumeric}}
{{#isDate}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = JsonSerializer.Deserialize<DateTime{{#isNullable}}?{{/isNullable}}>(ref reader, options);
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = JsonSerializer.Deserialize<DateTime{{#isNullable}}?{{/isNullable}}>(ref utf8JsonReader, jsonSerializerOptions);
{{/isDate}}
{{#isDateTime}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = JsonSerializer.Deserialize<DateTime{{#isNullable}}?{{/isNullable}}>(ref reader, options);
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = JsonSerializer.Deserialize<DateTime{{#isNullable}}?{{/isNullable}}>(ref utf8JsonReader, jsonSerializerOptions);
{{/isDateTime}}
{{#isEnum}}
{{^isMap}}
{{#isNumeric}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = ({{#isInnerEnum}}{{classname}}.{{/isInnerEnum}}{{{datatypeWithEnum}}}) reader.GetInt32();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = ({{#isInnerEnum}}{{classname}}.{{/isInnerEnum}}{{{datatypeWithEnum}}}) utf8JsonReader.GetInt32();
{{/isNumeric}}
{{^isNumeric}}
string {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}RawValue = reader.GetString();
string {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}RawValue = utf8JsonReader.GetString();
{{^isInnerEnum}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = {{{datatypeWithEnum}}}Converter.FromString{{#isNullable}}OrDefault{{/isNullable}}({{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}RawValue);
{{/isInnerEnum}}
@@ -124,7 +124,7 @@
{{/isMap}}
{{/isEnum}}
{{#isUuid}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = reader.GetGuid();
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = utf8JsonReader.GetGuid();
{{/isUuid}}
{{^isUuid}}
{{^isEnum}}
@@ -133,7 +133,7 @@
{{^isNumeric}}
{{^isDate}}
{{^isDateTime}}
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = JsonSerializer.Deserialize<{{{datatypeWithEnum}}}>(ref reader, options);
{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} = JsonSerializer.Deserialize<{{{datatypeWithEnum}}}>(ref utf8JsonReader, jsonSerializerOptions);
{{/isDateTime}}
{{/isDate}}
{{/isNumeric}}
@@ -167,9 +167,9 @@
/// </summary>
/// <param name="writer"></param>
/// <param name="{{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}"></param>
/// <param name="options"></param>
/// <param name="jsonSerializerOptions"></param>
/// <exception cref="NotImplementedException"></exception>
public override void Write(Utf8JsonWriter writer, {{classname}} {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}, JsonSerializerOptions options)
public override void Write(Utf8JsonWriter writer, {{classname}} {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}, JsonSerializerOptions jsonSerializerOptions)
{
writer.WriteStartObject();
@@ -209,11 +209,11 @@
{{/isEnum}}
{{#isDate}}
writer.WritePropertyName("{{baseName}}");
JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}}, options);
JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}}, jsonSerializerOptions);
{{/isDate}}
{{#isDateTime}}
writer.WritePropertyName("{{baseName}}");
JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}}, options);
JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}}, jsonSerializerOptions);
{{/isDateTime}}
{{#isEnum}}
{{#isNumeric}}
@@ -243,7 +243,15 @@
{{/isMap}}
{{/isEnum}}
{{#isUuid}}
{{^isNullable}}
writer.WriteString("{{baseName}}", {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}});
{{/isNullable}}
{{#isNullable}}
if ({{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}} == null)
writer.WriteNull("{{baseName}}");
else
writer.WriteString("{{baseName}}", {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}}.Value);
{{/isNullable}}
{{/isUuid}}
{{^isUuid}}
{{^isEnum}}
@@ -253,7 +261,7 @@
{{^isDate}}
{{^isDateTime}}
writer.WritePropertyName("{{baseName}}");
JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}}, options);
JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{name}}, jsonSerializerOptions);
{{/isDateTime}}
{{/isDate}}
{{/isNumeric}}

View File

@@ -1 +1 @@
{{#parentModel.composedSchemas.allOf}}{{^isInherited}}{{#lambda.camelcase_param}}{{parent}}{{/lambda.camelcase_param}}.{{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}} {{/isInherited}}{{/parentModel.composedSchemas.allOf}}{{#parentModel.composedSchemas.anyOf}}{{#lambda.camelcase_param}}{{parent}}}{{/lambda.camelcase_param}}.{{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}} {{/parentModel.composedSchemas.anyOf}}{{#allVars}}{{#isInherited}}{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} {{/isInherited}}{{/allVars}}
{{#parentModel.composedSchemas.allOf}}{{^isInherited}}{{#lambda.camelcase_param}}{{parent}}{{/lambda.camelcase_param}}.{{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}} {{/isInherited}}{{/parentModel.composedSchemas.allOf}}{{#parentModel.composedSchemas.anyOf}}{{#lambda.camelcase_param}}{{parent}}{{/lambda.camelcase_param}}.{{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}} {{/parentModel.composedSchemas.anyOf}}{{#allVars}}{{#isInherited}}{{^isNew}}{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}{{/isNew}}{{#isNew}}{{#isEnum}}{{#isInnerEnum}}{{classname}}.{{/isInnerEnum}}{{{datatypeWithEnum}}}ToJsonValue({{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}){{/isEnum}}{{^isEnum}}{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}.ToString(){{/isEnum}}{{/isNew}} {{/isInherited}}{{/allVars}}

View File

@@ -125,7 +125,7 @@
{{#deprecated}}
[Obsolete]
{{/deprecated}}
public {{>PropertyDataType}} {{name}} { get; {{^isReadOnly}}set; {{/isReadOnly}}}
public {{#isNew}}new {{/isNew}}{{>PropertyDataType}} {{name}} { get; {{^isReadOnly}}set; {{/isReadOnly}}}
{{/isEnum}}
{{/vars}}
@@ -165,8 +165,22 @@
{{/isInherited}}
{{/composedSchemas.allOf}}
{{#allVars}}
{{^isInherited}}
{{^isEnum}}
{{#isInherited}}
{{#isNew}}
/// <summary>
/// {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
/// </summary>{{#description}}
/// <value>{{.}}</value>{{/description}}
[JsonPropertyName("{{baseName}}")]
{{#deprecated}}
[Obsolete]
{{/deprecated}}
public new {{#isNullable}}{{#lambda.optional}}{{{datatypeWithEnum}}}{{/lambda.optional}}{{/isNullable}}{{^isNullable}}{{{datatypeWithEnum}}}{{/isNullable}} {{name}} { get; {{^isReadOnly}}set; {{/isReadOnly}}}
{{/isNew}}
{{/isInherited}}
{{^isInherited}}
/// <summary>
/// {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
/// </summary>{{#description}}
@@ -177,8 +191,8 @@
{{/deprecated}}
public {{#isNullable}}{{#lambda.optional}}{{{datatypeWithEnum}}}{{/lambda.optional}}{{/isNullable}}{{^isNullable}}{{{datatypeWithEnum}}}{{/isNullable}} {{name}} { get; {{^isReadOnly}}set; {{/isReadOnly}}}
{{/isEnum}}
{{/isInherited}}
{{/isEnum}}
{{/allVars}}
{{#isAdditionalPropertiesTrue}}
{{^parentModel}}

View File

@@ -284,7 +284,7 @@ defmodule {{moduleName}}.Connection do
def authorization(token, scopes \\ @default_scopes)
def authorization(token, _scopes) when is_binary(token) do
{Tesla.Middlware.Headers, ["authorization", token]}
{Tesla.Middleware.Headers, ["authorization", token]}
end
def authorization({module, function}, scopes) when is_atom(module) and is_atom(function) do

View File

@@ -101,7 +101,12 @@ defmodule {{moduleName}}.RequestBuilder do
end
def add_param(request, :headers, key, value) do
Tesla.put_header(request, key, value)
headers =
request
|> Map.get(:headers, [])
|> List.keystore(key, 0, {key, value})
Map.put(request, :headers, headers)
end
def add_param(request, :file, name, path) do

View File

@@ -112,22 +112,22 @@ func EncodeJSONResponse(i interface{}, status *int,{{#addResponseHeaders}} heade
}
// ReadFormFileToTempFile reads file data from a request form and writes it to a temporary file
func ReadFormFileToTempFile(r *http.Request, key string) (os.File, error) {
func ReadFormFileToTempFile(r *http.Request, key string) (*os.File, error) {
_, fileHeader, err := r.FormFile(key)
if err != nil {
return os.File{}, err
return nil, err
}
return readFileHeaderToTempFile(fileHeader)
}
// ReadFormFilesToTempFiles reads files array data from a request form and writes it to a temporary files
func ReadFormFilesToTempFiles(r *http.Request, key string) ([]os.File, error) {
func ReadFormFilesToTempFiles(r *http.Request, key string) ([]*os.File, error) {
if err := r.ParseMultipartForm(32 << 20); err != nil {
return nil, err
}
files := make([]os.File, 0, len(r.MultipartForm.File[key]))
files := make([]*os.File, 0, len(r.MultipartForm.File[key]))
for _, fileHeader := range r.MultipartForm.File[key] {
file, err := readFileHeaderToTempFile(fileHeader)
@@ -142,29 +142,29 @@ func ReadFormFilesToTempFiles(r *http.Request, key string) ([]os.File, error) {
}
// readFileHeaderToTempFile reads multipart.FileHeader and writes it to a temporary file
func readFileHeaderToTempFile(fileHeader *multipart.FileHeader) (os.File, error) {
func readFileHeaderToTempFile(fileHeader *multipart.FileHeader) (*os.File, error) {
formFile, err := fileHeader.Open()
if err != nil {
return os.File{}, err
return nil, err
}
defer formFile.Close()
fileBytes, err := ioutil.ReadAll(formFile)
if err != nil {
return os.File{}, err
return nil, err
}
file, err := ioutil.TempFile("", fileHeader.Filename)
if err != nil {
return os.File{}, err
return nil, err
}
defer file.Close()
file.Write(fileBytes)
return *file, nil
return file, nil
}
// parseInt64Parameter parses a string parameter to an int64.

View File

@@ -39,7 +39,7 @@ type {{classname}} interface {
{{#isDeprecated}}
// Deprecated
{{/isDeprecated}}
{{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}*{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error)
{{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error)
{{/operation}}
}
{{/generateInterfaces}}
@@ -55,7 +55,7 @@ type {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/stru
ApiService *{{classname}}Service
{{/generateInterfaces}}
{{#allParams}}
{{paramName}} {{^isPathParam}}*{{/isPathParam}}{{{dataType}}}
{{paramName}} {{^isPathParam}}{{^isFile}}*{{/isFile}}{{/isPathParam}}{{{dataType}}}
{{/allParams}}
}
@@ -68,13 +68,13 @@ type {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/stru
// Deprecated
{{/isDeprecated}}
func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) {{vendorExtensions.x-export-param-name}}({{paramName}} {{{dataType}}}) {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request {
r.{{paramName}} = &{{paramName}}
r.{{paramName}} = {{^isFile}}&{{/isFile}}{{paramName}}
return r
}
{{/isPathParam}}
{{/allParams}}
func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) Execute() ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}*{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) {
func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) Execute() ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) {
return r.ApiService.{{nickname}}Execute(r)
}
@@ -108,13 +108,13 @@ func (a *{{{classname}}}Service) {{{nickname}}}(ctx context.Context{{#pathParams
{{#isDeprecated}}
// Deprecated
{{/isDeprecated}}
func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}*{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) {
func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) {
var (
localVarHTTPMethod = http.Method{{httpMethod}}
localVarPostBody interface{}
formFiles []formFile
{{#returnType}}
localVarReturnValue {{^isArray}}{{^returnTypeIsPrimitive}}*{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}
localVarReturnValue {{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}
{{/returnType}}
)
@@ -258,27 +258,17 @@ func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&class
{{paramName}}LocalVarFormFileName = "{{baseName}}"
{{#required}}
{{paramName}}LocalVarFile := r.{{paramName}}
{{/required}}
{{^required}}
var {{paramName}}LocalVarFile *{{dataType}}
if r.{{paramName}} != nil {
{{paramName}}LocalVarFile = r.{{paramName}}
}
if {{paramName}}LocalVarFile != nil {
fbs, _ := ioutil.ReadAll({{paramName}}LocalVarFile)
{{/required}}
{{#required}}
fbs, _ := ioutil.ReadAll({{paramName}}LocalVarFile)
{{/required}}
{{paramName}}LocalVarFileBytes = fbs
{{paramName}}LocalVarFileName = {{paramName}}LocalVarFile.Name()
{{paramName}}LocalVarFile.Close()
{{^required}}
formFiles = append(formFiles, formFile{fileBytes: {{paramName}}LocalVarFileBytes, fileName: {{paramName}}LocalVarFileName, formFileName: {{paramName}}LocalVarFormFileName})
}
{{/required}}
formFiles = append(formFiles, formFile{fileBytes: {{paramName}}LocalVarFileBytes, fileName: {{paramName}}LocalVarFileName, formFileName: {{paramName}}LocalVarFormFileName})
{{/isFile}}
{{^isFile}}
{{#required}}

View File

@@ -225,7 +225,11 @@ func parameterAddToQuery(queryParams interface{}, keyPrefix string, obj interfac
switch valuesMap := queryParams.(type) {
case url.Values:
valuesMap.Add( keyPrefix, value )
if collectionType == "csv" && valuesMap.Get(keyPrefix) != "" {
valuesMap.Set(keyPrefix, valuesMap.Get(keyPrefix) + "," + value)
} else {
valuesMap.Add(keyPrefix, value)
}
break
case map[string]string:
valuesMap[keyPrefix] = value

View File

@@ -67,6 +67,12 @@ const (
// Calculate the message signature using probabilistic signature scheme RSASSA-PSS.
// PSS is randomized and will produce a different signature value each time.
HttpSigningAlgorithmRsaPSS string = "RSASSA-PSS"
// HashAlgorithm Sha256 for generating hash
HttpHashAlgorithmSha256 string = "sha256"
// HashAlgorithm Sha512 for generating hash
HttpHashAlgorithmSha512 string = "sha512"
)
var supportedSigningSchemes = map[string]bool{
@@ -107,6 +113,7 @@ type HttpSignatureAuth struct {
// The signature algorithm, when signing HTTP requests.
// Supported values are RSASSA-PKCS1-v1_5, RSASSA-PSS.
SigningAlgorithm string
HashAlgorithm string // supported values are sha256 and sha512. This also allows using sha256 with hs2019, which defaults to sha512.
SignedHeaders []string // A list of HTTP headers included when generating the signature for the message.
// SignatureMaxValidity specifies the maximum duration of the signature validity.
// The value is used to set the '(expires)' signature parameter in the HTTP request.
@@ -270,13 +277,22 @@ func SignRequest(
}
// Determine the cryptographic hash to be used for the signature and the body digest.
switch auth.SigningScheme {
case HttpSigningSchemeRsaSha512, HttpSigningSchemeHs2019:
case HttpSigningSchemeRsaSha512:
h = crypto.SHA512
prefix = "SHA-512="
case HttpSigningSchemeRsaSha256:
// This is deprecated and should no longer be used.
h = crypto.SHA256
prefix = "SHA-256="
case HttpSigningSchemeHs2019:
if auth.HashAlgorithm == HttpHashAlgorithmSha256 {
h = crypto.SHA256
prefix = "SHA-256="
} else {
h = crypto.SHA512
prefix = "SHA-512="
}
default:
return fmt.Errorf("unsupported signature scheme: %v", auth.SigningScheme)
}

View File

@@ -128,7 +128,7 @@ Do not edit the class manually.
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.1.11</version>
<version>2.2.7</version>
</dependency>
{{/oas3}}
{{#jackson}}

View File

@@ -26,7 +26,7 @@
<swagger-annotations-version>1.6.5</swagger-annotations-version>
{{/generateSwagger1Annotations}}
{{#generateSwagger2Annotations}}
<swagger-annotations-version>2.2.0</swagger-annotations-version>
<swagger-annotations-version>2.2.7</swagger-annotations-version>
{{/generateSwagger2Annotations}}
</properties>

View File

@@ -190,7 +190,7 @@ Declare the class with extends and implements
@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}")
{{/generateSwagger1Annotations}}
{{#generateSwagger2Annotations}}
@Schema(name = "{{{baseName}}}", {{#isReadOnly}}accessMode = Schema.AccessMode.READ_ONLY, {{/isReadOnly}}{{#example}}example = "{{{.}}}", {{/example}}{{#description}}description = "{{{.}}}", {{/description}}required = {{{required}}})
@Schema(name = "{{{baseName}}}"{{#isReadOnly}}, accessMode = Schema.AccessMode.READ_ONLY{{/isReadOnly}}{{#example}}, example = "{{{.}}}"{{/example}}{{#description}}, description = "{{{.}}}"{{/description}}, requiredMode = {{#required}}Schema.RequiredMode.REQUIRED{{/required}}{{^required}}Schema.RequiredMode.NOT_REQUIRED{{/required}})
{{/generateSwagger2Annotations}}
{{#vendorExtensions.x-extra-annotation}}
{{{vendorExtensions.x-extra-annotation}}}

View File

@@ -13,5 +13,6 @@ package {{packageName}}.infrastructure
val path: String,
val headers: MutableMap<String, String> = mutableMapOf(),
val query: MutableMap<String, List<String>> = mutableMapOf(),
val requiresAuthentication: Boolean,
val body: T? = null
)

View File

@@ -82,7 +82,8 @@ import com.fasterxml.jackson.databind.ObjectMapper
RequestMethod.{{httpMethod}},
"{{path}}"{{#pathParams}}.replace("{" + "{{baseName}}" + "}", "${{{paramName}}}"){{/pathParams}},
query = localVariableQuery,
headers = localVariableHeaders
headers = localVariableHeaders,
requiresAuthentication = {{#hasAuthMethods}}true{{/hasAuthMethods}}{{^hasAuthMethods}}false{{/hasAuthMethods}},
)
return {{#hasBodyParam}}jsonRequest{{/hasBodyParam}}{{^hasBodyParam}}{{#hasFormParams}}{{#isMultipart}}multipartFormRequest{{/isMultipart}}{{^isMultipart}}urlEncodedFormRequest{{/isMultipart}}{{/hasFormParams}}{{^hasFormParams}}request{{/hasFormParams}}{{/hasBodyParam}}(

View File

@@ -228,6 +228,7 @@ import {{packageName}}.infrastructure.toMultiValue
path = "{{path}}"{{#pathParams}}.replace("{"+"{{baseName}}"+"}", encodeURIComponent({{#isContainer}}{{paramName}}.joinToString(","){{/isContainer}}{{^isContainer}}{{{paramName}}}{{#isEnum}}.value{{/isEnum}}.toString(){{/isContainer}})){{/pathParams}},
query = localVariableQuery,
headers = localVariableHeaders,
requiresAuthentication = {{#hasAuthMethods}}true{{/hasAuthMethods}}{{^hasAuthMethods}}false{{/hasAuthMethods}},
body = localVariableBody
)
}

View File

@@ -68,7 +68,8 @@ import kotlinx.serialization.encoding.*
RequestMethod.{{httpMethod}},
"{{path}}"{{#pathParams}}.replace("{" + "{{baseName}}" + "}", {{#isContainer}}{{paramName}}.joinToString(","){{/isContainer}}{{^isContainer}}"${{{paramName}}}"{{/isContainer}}){{/pathParams}},
query = localVariableQuery,
headers = localVariableHeaders
headers = localVariableHeaders,
requiresAuthentication = {{#hasAuthMethods}}true{{/hasAuthMethods}}{{^hasAuthMethods}}false{{/hasAuthMethods}},
)
return {{#hasBodyParam}}jsonRequest{{/hasBodyParam}}{{^hasBodyParam}}{{#hasFormParams}}{{#isMultipart}}multipartFormRequest{{/isMultipart}}{{^isMultipart}}urlEncodedFormRequest{{/isMultipart}}{{/hasFormParams}}{{^hasFormParams}}request{{/hasFormParams}}{{/hasBodyParam}}(

View File

@@ -1,4 +1,4 @@
{{#swagger2AnnotationLibrary}}
@Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}"){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}
@Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}requiredMode = Schema.RequiredMode.REQUIRED, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}"){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swagger1AnnotationLibrary}}
{{>modelMutable}} {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? {{^discriminator}}= {{{defaultValue}}}{{^defaultValue}}null{{/defaultValue}}{{/discriminator}}

View File

@@ -1,4 +1,4 @@
{{#swagger2AnnotationLibrary}}
@Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}"){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}
@Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}requiredMode = Schema.RequiredMode.REQUIRED, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}"){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swagger1AnnotationLibrary}}
{{>modelMutable}} {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}

View File

@@ -7,12 +7,7 @@ from {{{packageName}}}.rest import ApiException
from pprint import pprint
{{> python_doc_auth_partial}}
# Enter a context with an instance of the API client
{{#hasAuthMethods}}
{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient(configuration) as api_client:
{{/hasAuthMethods}}
{{^hasAuthMethods}}
{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient() as api_client:
{{/hasAuthMethods}}
# Create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}(api_client)
{{#allParams}}

View File

@@ -65,6 +65,33 @@ import Vapor
return requestTask
}
{{#useAsyncAwait}}
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
@discardableResult
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute() async throws -> Response<T> {
return try await withTaskCancellationHandler {
try Task.checkCancellation()
return try await withCheckedThrowingContinuation { continuation in
guard !Task.isCancelled else {
continuation.resume(throwing: CancellationError())
return
}
self.execute { result in
switch result {
case let .success(response):
continuation.resume(returning: response)
case let .failure(error):
continuation.resume(throwing: error)
}
}
}
} onCancel: {
self.requestTask.cancel()
}
}
{{/useAsyncAwait}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func addHeader(name: String, value: String) -> Self {
if !value.isEmpty {
headers[name] = value

View File

@@ -173,9 +173,10 @@ extension {{projectName}}API {
{{/isDeprecated}}
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> AnyPublisher<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}, Error> {
var requestTask: RequestTask?
let requestBuilder = {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}})
let requestTask = requestBuilder.requestTask
return Future<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}, Error> { promise in
requestTask = {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}).execute { result in
requestBuilder.execute { result in
switch result {
{{#returnType}}
case let .success(response):
@@ -191,7 +192,7 @@ extension {{projectName}}API {
}
}
.handleEvents(receiveCancel: {
requestTask?.cancel()
requestTask.cancel()
})
.eraseToAnyPublisher()
}
@@ -211,34 +212,7 @@ extension {{projectName}}API {
{{/isDeprecated}}
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) async throws{{#returnType}} -> {{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{/returnType}} {
let requestBuilder = {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}})
let requestTask = requestBuilder.requestTask
return try await withTaskCancellationHandler {
try Task.checkCancellation()
return try await withCheckedThrowingContinuation { continuation in
guard !Task.isCancelled else {
continuation.resume(throwing: CancellationError())
return
}
requestBuilder.execute { result in
switch result {
{{#returnType}}
case let .success(response):
continuation.resume(returning: response.body)
{{/returnType}}
{{^returnType}}
case .success:
continuation.resume(returning: ())
{{/returnType}}
case let .failure(error):
continuation.resume(throwing: error)
}
}
}
} onCancel: {
requestTask.cancel()
}
return try await {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}).execute().body
}
{{/useAsyncAwait}}
{{#useResult}}

View File

@@ -4189,6 +4189,9 @@ public class DefaultCodegenTest {
assertEquals(cp.complexType, "coordinates");
assertEquals(cp.baseName, "SchemaFor201ResponseBodyApplicationJson");
assertNotNull(mt.getExamples());
assertEquals(mt.getExamples().size(), 2);
mt = content.get("text/plain");
assertNull(mt.getEncoding());
cp = mt.getSchema();
@@ -4301,7 +4304,8 @@ public class DefaultCodegenTest {
}
@Test
public void testOpenAPINormalizer() {
public void testOpenAPINormalizerRefAsParentInAllOf() {
// to test the rule REF_AS_PARENT_IN_ALLOF
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/allOf_extension_parent.yaml");
Schema schema = openAPI.getComponents().getSchemas().get("AnotherPerson");
@@ -4324,4 +4328,56 @@ public class DefaultCodegenTest {
Schema schema5 = openAPI.getComponents().getSchemas().get("Person");
assertEquals(schema5.getExtensions().get("x-parent"), "abstract");
}
@Test
public void testOpenAPINormalizerEnableKeepOnlyFirstTagInOperation() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getTags().size(), 2);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getTags().size(), 1);
Map<String, String> options = new HashMap<>();
options.put("KEEP_ONLY_FIRST_TAG_IN_OPERATION", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getTags().size(), 1);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getTags().size(), 1);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getTags().get(0), "person");
}
@Test
public void testOpenAPINormalizerRemoveAnyOfOneOfAndKeepPropertiesOnly() {
// to test the rule REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIIES_ONLY
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/removeAnyOfOneOfAndKeepPropertiesOnly_test.yaml");
Schema schema = openAPI.getComponents().getSchemas().get("Person");
assertEquals(schema.getAnyOf().size(), 2);
Map<String, String> options = new HashMap<>();
options.put("REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
Schema schema3 = openAPI.getComponents().getSchemas().get("Person");
assertNull(schema.getAnyOf());
}
@Test
public void testOpenAPINormalizerSimplifyOneOfAnyOfStringAndEnumString() {
// to test the rule SIMPLIFY_ONEOF_ANYOF_STRING_AND_ENUM_STRING
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/simplifyAnyOfStringAndEnumString_test.yaml");
Schema schema = openAPI.getComponents().getSchemas().get("AnyOfTest");
assertEquals(schema.getAnyOf().size(), 2);
Map<String, String> options = new HashMap<>();
options.put("SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
Schema schema3 = openAPI.getComponents().getSchemas().get("AnyOfTest");
assertNull(schema3.getAnyOf());
assertTrue(schema3 instanceof StringSchema);
}
}

View File

@@ -262,8 +262,8 @@ public class GoModelTest {
public void filePropertyTest() {
final DefaultCodegen codegen = new GoClientCodegen();
final Schema model1 = new Schema().type("file");
Assert.assertEquals(codegen.getSchemaType(model1), "os.File");
Assert.assertEquals(codegen.getTypeDeclaration(model1), "os.File");
Assert.assertEquals(codegen.getSchemaType(model1), "*os.File");
Assert.assertEquals(codegen.getTypeDeclaration(model1), "*os.File");
final Schema model2 = new Schema().$ref("#/definitions/File");
Assert.assertEquals(codegen.getSchemaType(model2), "File");

View File

@@ -23,6 +23,7 @@ import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import org.openapitools.codegen.*;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.languages.AbstractJavaCodegen;
import org.openapitools.codegen.languages.JavaCXFClientCodegen;
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
@@ -34,10 +35,18 @@ import org.openapitools.codegen.model.OperationsMap;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.openapitools.codegen.TestUtils.validateJavaSourceFiles;
public class JavaCXFClientCodegenTest {
@Test
@@ -299,4 +308,41 @@ public class JavaCXFClientCodegenTest {
Assert.assertEquals(codegen.additionalProperties().get(AbstractJavaCodegen.JACKSON), Boolean.TRUE);
Assert.assertTrue(codegen.isUseJackson());
}
@Test
public void testUseAbstractionForFiles() throws Exception {
Map<String, Object> properties = new HashMap<>();
properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api");
properties.put(CodegenConstants.MODEL_PACKAGE, "xyz.abcdef.api");
properties.put(JavaCXFClientCodegen.USE_ABSTRACTION_FOR_FILES, true);
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("jaxrs-cxf-client")
.setAdditionalProperties(properties)
.setInputSpec("src/test/resources/3_0/issue8792.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
files.forEach(File::deleteOnExit);
validateJavaSourceFiles(files);
Path defaultApi = Paths.get(output + "/src/gen/java/xyz/abcdef/api/DefaultApi.java");
TestUtils.assertFileContains(defaultApi,
//get file
"@ApiResponse(code = 200, message = \"File content\", response = InputStream.class)",
"public InputStream filesIdGet(@PathParam(\"id\") String id);",
//upload
"public FilesUploadPost200Response filesUploadPost(InputStream body);"
);
}
}

View File

@@ -24,7 +24,10 @@ import static org.openapitools.codegen.TestUtils.assertFileNotContains;
import static org.openapitools.codegen.languages.SpringCodegen.INTERFACE_ONLY;
import static org.openapitools.codegen.languages.SpringCodegen.REQUEST_MAPPING_OPTION;
import static org.openapitools.codegen.languages.SpringCodegen.RESPONSE_WRAPPER;
import static org.openapitools.codegen.languages.SpringCodegen.RETURN_SUCCESS_CODE;
import static org.openapitools.codegen.languages.SpringCodegen.SPRING_BOOT;
import static org.openapitools.codegen.languages.SpringCodegen.USE_SPRING_BOOT3;
import static org.openapitools.codegen.languages.features.DocumentationProviderFeatures.ANNOTATION_LIBRARY;
import static org.openapitools.codegen.languages.features.DocumentationProviderFeatures.DOCUMENTATION_PROVIDER;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
@@ -47,6 +50,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.openapitools.codegen.config.GlobalSettings;
import org.openapitools.codegen.java.assertions.JavaFileAssert;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.ClientOptInput;
@@ -595,7 +599,7 @@ public class SpringCodegenTest {
// Check that api validates mixed multipart request
JavaFileAssert.assertThat(files.get("MultipartMixedApi.java"))
.assertMethod("multipartMixed", "MultipartMixedStatus", "MultipartFile", "MultipartMixedRequestMarker")
.assertMethod("multipartMixed", "MultipartMixedStatus", "MultipartFile", "MultipartMixedRequestMarker", "List<MultipartMixedStatus>")
.hasParameter("status").withType("MultipartMixedStatus")
.assertParameterAnnotations()
.containsWithName("Valid")
@@ -608,7 +612,47 @@ public class SpringCodegenTest {
.toParameter().toMethod()
.hasParameter("marker").withType("MultipartMixedRequestMarker")
.assertParameterAnnotations()
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"marker\"", "required", "false"));
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"marker\"", "required", "false"))
.toParameter().toMethod()
.hasParameter("statusArray").withType("List<MultipartMixedStatus>")
.assertParameterAnnotations()
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"statusArray\"", "required", "false"));
}
@Test
public void shouldAddParameterWithInHeaderWhenImplicitHeadersIsTrue_issue14418() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
OpenAPI openAPI = new OpenAPIParser()
.readLocation("src/test/resources/bugs/issue_14418.yaml", null, new ParseOptions()).getOpenAPI();
SpringCodegen codegen = new SpringCodegen();
codegen.setLibrary(SPRING_BOOT);
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(SpringCodegen.INTERFACE_ONLY, "true");
codegen.additionalProperties().put(SpringCodegen.USE_BEANVALIDATION, "true");
codegen.additionalProperties().put(SpringCodegen.PERFORM_BEANVALIDATION, "true");
codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "xyz.model");
codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "xyz.controller");
codegen.additionalProperties().put(SpringCodegen.IMPLICIT_HEADERS, "true");
ClientOptInput input = new ClientOptInput()
.openAPI(openAPI)
.config(codegen);
DefaultGenerator generator = new DefaultGenerator();
Map<String, File> files = generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));
JavaFileAssert.assertThat(files.get("TestApi.java"))
.isInterface()
.hasImports("io.swagger.v3.oas.annotations.enums.ParameterIn")
.assertMethod("test")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Parameters", ImmutableMap.of(
"value", "{ @Parameter(name = \"testHeader\", description = \"Test header\", required = true, in = ParameterIn.HEADER) }"
// in = ParameterIn.HEADER is missing?!
));
}
// Helper function, intended to reduce boilerplate
@@ -1400,6 +1444,53 @@ public class SpringCodegenTest {
.assertMethod("getWithMapOfStrings").hasReturnType("ResponseEntity<Map<String, String>>");
}
@Test
public void testResponseWithArray_issue12524() throws Exception {
GlobalSettings.setProperty("skipFormModel", "true");
try {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put(DOCUMENTATION_PROVIDER, "none");
additionalProperties.put(ANNOTATION_LIBRARY, "none");
additionalProperties.put(RETURN_SUCCESS_CODE, "true");
Map<String, File> files = generateFromContract("src/test/resources/bugs/issue_12524.json", SPRING_BOOT, additionalProperties);
JavaFileAssert.assertThat(files.get("API01ListOfStuff.java"))
.hasImports("com.fasterxml.jackson.annotation.JsonTypeName");
} finally {
GlobalSettings.reset();
}
}
@Test
public void paramObjectImportForDifferentSpringBootVersions_issue14077() throws Exception {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put(SpringCodegen.USE_TAGS, "true");
additionalProperties.put(DOCUMENTATION_PROVIDER, "springdoc");
additionalProperties.put(SpringCodegen.INTERFACE_ONLY, "true");
additionalProperties.put(SpringCodegen.SKIP_DEFAULT_INTERFACE, "true");
Map<String, File> files = generateFromContract("src/test/resources/2_0/petstore-with-spring-pageable.yaml", SPRING_BOOT, additionalProperties);
JavaFileAssert.assertThat(files.get("PetApi.java"))
.hasImports("org.springdoc.api.annotations.ParameterObject")
.assertMethod("findPetsByStatus")
.hasParameter("pageable").withType("Pageable")
.assertParameterAnnotations()
.containsWithName("ParameterObject");
// different import for SB3
additionalProperties.put(USE_SPRING_BOOT3, "true");
files = generateFromContract("src/test/resources/2_0/petstore-with-spring-pageable.yaml", SPRING_BOOT, additionalProperties);
JavaFileAssert.assertThat(files.get("PetApi.java"))
.hasImports("org.springdoc.core.annotations.ParameterObject")
.assertMethod("findPetsByStatus")
.hasParameter("pageable").withType("Pageable")
.assertParameterAnnotations()
.containsWithName("ParameterObject");
}
@Test
public void shouldSetDefaultValueForMultipleArrayItems() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();

View File

@@ -18,17 +18,28 @@
package org.openapitools.codegen.python;
import com.google.common.collect.Sets;
import io.swagger.parser.OpenAPIParser;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.PythonNextgenClientCodegen;
import org.openapitools.codegen.languages.features.CXFServerFeatures;
import static org.openapitools.codegen.TestUtils.assertFileContains;
import static org.openapitools.codegen.TestUtils.assertFileExists;
import org.openapitools.codegen.TestUtils;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PythonNextgenClientCodegenTest {
@@ -382,4 +393,34 @@ public class PythonNextgenClientCodegenTest {
Assert.assertEquals(cm.parent, null);
Assert.assertEquals(cm.imports.size(), 0);
}
@Test(description ="check API example has input param(configuration) when it creates api_client")
public void apiExampleDocTest() throws Exception {
final DefaultCodegen codegen = new PythonNextgenClientCodegen();
final String outputPath = generateFiles(codegen, "src/test/resources/3_0/generic.yaml");
final Path p = Paths.get(outputPath + "docs/DefaultApi.md");
assertFileExists(p);
assertFileContains(p, "openapi_client.ApiClient(configuration) as api_client");
}
// Helper function, intended to reduce boilerplate
static private String generateFiles(DefaultCodegen codegen, String filePath) throws IOException {
final File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
final String outputPath = output.getAbsolutePath().replace('\\', '/');
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true");
final ClientOptInput input = new ClientOptInput();
final OpenAPI openAPI = new OpenAPIParser().readLocation(filePath, null, new ParseOptions()).getOpenAPI();
input.openAPI(openAPI);
input.config(codegen);
final DefaultGenerator generator = new DefaultGenerator();
final List<File> files = generator.opts(input).generate();
Assert.assertTrue(files.size() > 0);
return outputPath + "/";
}
}

View File

@@ -44,6 +44,15 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/coordinates'
examples:
Example Amsterdam coordinates:
value:
lat: 52.377956
long: 4.897070
Example San Francisco coordinates:
value:
lat: 37.773972
long: -122.431297
text/plain:
schema:
$ref: '#/components/schemas/stringWithMinLength'
@@ -58,6 +67,15 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/coordinates'
examples:
Example Amsterdam coordinates:
value:
lat: 52.377956
long: 4.897070
Example San Francisco coordinates:
value:
lat: 37.773972
long: -122.431297
text/plain:
schema:
$ref: '#/components/schemas/stringWithMinLength'

View File

@@ -2179,3 +2179,11 @@ components:
type: string
prop2:
type: object
NullableGuidClass:
type: object
properties:
uuid:
type: string
format: uuid
example: 72f98069-206d-4f12-9f12-3d1e525a8e84
nullable: true

View File

@@ -137,6 +137,27 @@ paths:
text/plain:
schema:
type: string
/query/style_form/explode_true/object/allOf:
get:
tags:
- query
summary: Test query parameter(s)
description: Test query parameter(s)
operationId: test/query/style_form/explode_true/object/allOf
parameters:
- in: query
name: query_object
style: form #default
explode: true #default
schema:
$ref: '#/components/schemas/DataQuery'
responses:
'200':
description: Successful operation
content:
text/plain:
schema:
type: string
/query/style_deepObject/explode_true/object:
get:
tags:
@@ -158,6 +179,29 @@ paths:
text/plain:
schema:
type: string
/query/style_deepObject/explode_true/object/allOf:
get:
tags:
- query
summary: Test query parameter(s)
description: Test query parameter(s)
operationId: test/query/style_deepObject/explode_true/object/allOf
parameters:
- in: query
name: query_object
style: deepObject
explode: true #default
schema:
allOf:
- $ref: '#/components/schemas/Bird'
- $ref: '#/components/schemas/Category'
responses:
'200':
description: Successful operation
content:
text/plain:
schema:
type: string
/echo/body/Pet:
post:
tags:
@@ -244,3 +288,45 @@ components:
- sold
xml:
name: pet
Bird:
type: object
properties:
size:
type: string
color:
type: string
Query:
type: object
x-parent: true
properties:
id:
type: integer
description: Query
format: int64
outcomes:
type: array
items:
type: string
enum:
- SUCCESS
- FAILURE
- SKIPPED
default:
- SUCCESS
- FAILURE
DataQuery:
allOf:
- type: object
properties:
suffix:
type: string
description: test suffix
text:
type: string
description: Some text containing white spaces
example: "Some text"
date:
type: string
format: date-time
description: A date
- $ref: '#/components/schemas/Query'

View File

@@ -0,0 +1,59 @@
openapi: 3.0.1
info:
version: 1.0.0
title: Example
license:
name: MIT
servers:
- url: http://api.example.xyz/v1
paths:
/person/display/{personId}:
get:
tags:
- person
- basic
parameters:
- name: personId
in: path
required: true
description: The id of the person to retrieve
schema:
type: string
operationId: list
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Person"
delete:
tags:
- person
parameters:
- name: personId
in: path
required: true
description: The id of the person to retrieve
schema:
type: string
operationId: delete
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Person"
components:
schemas:
Person:
description: person
type: object
properties:
$_type:
type: string
lastName:
type: string
firstName:
type: string

View File

@@ -70,6 +70,10 @@ paths:
description: "a file"
type: string
format: binary
statusArray:
type: array
items:
$ref: '#/components/schemas/MultipartMixedStatus'
responses:
'204':
description: Successful operation
@@ -82,4 +86,4 @@ components:
- ALLOWED
- IN_PROGRESS
- REJECTED
example: REJECTED
example: REJECTED

View File

@@ -2051,3 +2051,10 @@ components:
- type: string
- format: date-time
type: string
AllOfPrimitiveTypes:
allOf:
- type: object
properties:
test:
type: string
format: date-time

View File

@@ -0,0 +1,52 @@
openapi: 3.0.0
info:
title: test useAbstractionForFiles for jaxrs-cxf
version: 0.0.1
servers:
- url: "http://localhost"
paths:
/files/{id}:
get:
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
200:
description: File content
content:
application/octet-stream:
schema:
type: string
format: binary
500:
description: error message
content:
application/json:
schema:
type: object
properties:
errormsg:
type: string
/files/upload:
post:
requestBody:
required: true
description: The file content to upload
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
200:
description: id
content:
application/json:
schema:
type: object
properties:
id:
type: string

View File

@@ -0,0 +1,47 @@
openapi: 3.0.1
info:
version: 1.0.0
title: Example
license:
name: MIT
servers:
- url: http://api.example.xyz/v1
paths:
/person/display/{personId}:
get:
parameters:
- name: personId
in: path
required: true
description: The id of the person to retrieve
schema:
type: string
operationId: list
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Person"
components:
schemas:
Person:
description: person using anyOf with required properties
type: object
anyOf:
- required: [ specialName ]
- required: [ hiddenName ]
properties:
id:
type: string
lastName:
type: string
firstName:
type: string
nickName:
type: string
specialName:
type: string
hiddenName:
type: string

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