diff --git a/.github/workflows/check-supported-versions.yaml b/.github/workflows/check-supported-versions.yaml
index 3702fd30fb4..017b4bdf0ab 100644
--- a/.github/workflows/check-supported-versions.yaml
+++ b/.github/workflows/check-supported-versions.yaml
@@ -26,17 +26,17 @@ jobs:
- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v2
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: ${{ matrix.java }}
- - uses: actions/cache@v2.1.6
+ - uses: actions/cache@v2.1.7
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('pom.xml', 'modules/**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- - uses: actions/cache@v2.1.6
+ - uses: actions/cache@v2.1.7
with:
path: |
~/.gradle/caches
diff --git a/.github/workflows/gradle-test.yaml b/.github/workflows/gradle-test.yaml
index 755ca996a15..c6f6f495ab1 100644
--- a/.github/workflows/gradle-test.yaml
+++ b/.github/workflows/gradle-test.yaml
@@ -36,18 +36,18 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: 11
# Cache Gradle Dependencies
- name: Setup Gradle Dependencies Cache
- uses: actions/cache@v2
+ uses: actions/cache@v2.1.7
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-caches-${{ hashFiles('**/*.gradle', '**/*.gradle.kts') }}
# Cache Gradle Wrapper
- name: Setup Gradle Wrapper Cache
- uses: actions/cache@v2
+ uses: actions/cache@v2.1.7
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
diff --git a/.github/workflows/openapi-generator.yaml b/.github/workflows/openapi-generator.yaml
index aa1a94e21e9..b2e477592d4 100644
--- a/.github/workflows/openapi-generator.yaml
+++ b/.github/workflows/openapi-generator.yaml
@@ -17,11 +17,12 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: 8
+ distribution: 'temurin'
- name: Cache maven dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: cache-maven-repository
with:
@@ -52,11 +53,12 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: 8
+ distribution: 'temurin'
- name: Cache maven dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: cache-maven-repository
with:
@@ -86,9 +88,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: 8
+ distribution: 'temurin'
- name: Download openapi-generator-cli.jar artifact
uses: actions/download-artifact@v2.0.10
with:
@@ -124,9 +127,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: 8
+ distribution: 'temurin'
- name: Download openapi-generator-cli.jar artifact
uses: actions/download-artifact@v2.0.10
with:
@@ -158,11 +162,12 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: 11
+ distribution: 'temurin'
- name: Cache maven dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: cache-maven-repository
with:
@@ -190,11 +195,12 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: 11
+ distribution: 'temurin'
- name: Cache maven dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: cache-maven-repository
with:
diff --git a/.github/workflows/samples-dart.yaml b/.github/workflows/samples-dart.yaml
index 47ae424394d..5efe3b6b686 100644
--- a/.github/workflows/samples-dart.yaml
+++ b/.github/workflows/samples-dart.yaml
@@ -20,10 +20,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: 8
- name: Cache maven dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: maven-repository
with:
@@ -32,7 +32,7 @@ jobs:
~/.gradle
key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }}
- name: Cache test dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: pub-cache
with:
@@ -53,10 +53,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: 8
- name: Cache maven dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: maven-repository
with:
@@ -65,7 +65,7 @@ jobs:
~/.gradle
key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }}
- name: Cache test dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: pub-cache
with:
diff --git a/.github/workflows/samples-kotlin.yaml b/.github/workflows/samples-kotlin.yaml
index ddc46f801cb..d1d812cbadb 100644
--- a/.github/workflows/samples-kotlin.yaml
+++ b/.github/workflows/samples-kotlin.yaml
@@ -30,8 +30,7 @@ jobs:
#- samples/client/petstore/kotlin-json-request-string
- samples/client/petstore/kotlin-jvm-okhttp4-coroutines
- samples/client/petstore/kotlin-moshi-codegen
- # need some special setup
- #- samples/client/petstore/kotlin-multiplatform
+ - samples/client/petstore/kotlin-multiplatform
- samples/client/petstore/kotlin-nonpublic
- samples/client/petstore/kotlin-nullable
- samples/client/petstore/kotlin-okhttp3
@@ -45,10 +44,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: 8
- name: Cache maven dependencies
- uses: actions/cache@v2.1.6
+ uses: actions/cache@v2.1.7
env:
cache-name: maven-repository
with:
diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml
index d991e052a7d..63f622d66e1 100644
--- a/.github/workflows/sonar.yml
+++ b/.github/workflows/sonar.yml
@@ -16,7 +16,7 @@ jobs:
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: 11
- name: Compile with Maven
run: mvn -B -q clean install jacoco:report
diff --git a/README.md b/README.md
index 5774c216447..804104dd962 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
| | Languages/Frameworks |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later, .NET Standard 1.3 - 2.0, .NET Core 2.0, .NET 5.0. Libraries: RestSharp, HttpClient), **C++** (Arduino, cpp-restsdk, Qt5, Tizen, Unreal Engine 4), **Clojure**, **Crystal**, **Dart**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Apache HttpClient, Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client, MicroProfile Rest Client), **k6**, **Kotlin**, **Lua**, **Nim**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types, Apollo GraphQL DataStore), **Objective-C**, **OCaml**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (hyper, reqwest, rust-server), **Scala** (akka, http4s, scalaz, sttp, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x, 5.x), **Typescript** (AngularJS, Angular (2.x - 11.x), Aurelia, Axios, Fetch, Inversify, jQuery, Nestjs, Node, redux-query, Rxjs) |
-| **Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin, Echo), **Haskell** (Servant, Yesod), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples), [Vert.x](https://vertx.io/)), **Kotlin** (Spring Boot, Ktor, Vertx), **PHP** (Laravel, Lumen, [Mezzio (fka Zend Expressive)](https://github.com/mezzio/mezzio), Slim, Silex, [Symfony](https://symfony.com/)), **Python** (FastAPI, Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** (Akka, [Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra) |
+| **Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx, Azure Functions), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin, Echo), **Haskell** (Servant, Yesod), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples), [Vert.x](https://vertx.io/)), **Kotlin** (Spring Boot, Ktor, Vertx), **PHP** (Laravel, Lumen, [Mezzio (fka Zend Expressive)](https://github.com/mezzio/mezzio), Slim, Silex, [Symfony](https://symfony.com/)), **Python** (FastAPI, Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** (Akka, [Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra) |
| **API documentation generators** | **HTML**, **Confluence Wiki**, **Asciidoc**, **Markdown**, **PlantUML** |
| **Configuration files** | [**Apache2**](https://httpd.apache.org/) |
| **Others** | **GraphQL**, **JMeter**, **Ktorm**, **MySQL Schema**, **Protocol Buffer**, **WSDL** |
@@ -223,21 +223,21 @@ Examples:
# Execute latest released openapi-generator-cli
openapi-generator-cli version
-# Execute version 3.1.0 for the current invocation, regardless of the latest released version
-OPENAPI_GENERATOR_VERSION=3.1.0 openapi-generator-cli version
+# Execute version 4.1.0 for the current invocation, regardless of the latest released version
+OPENAPI_GENERATOR_VERSION=4.1.0 openapi-generator-cli version
-# Execute version 3.1.0-SNAPSHOT for the current invocation
-OPENAPI_GENERATOR_VERSION=3.1.0-SNAPSHOT openapi-generator-cli version
+# Execute version 4.1.0-SNAPSHOT for the current invocation
+OPENAPI_GENERATOR_VERSION=4.1.0-SNAPSHOT openapi-generator-cli version
-# Execute version 3.0.2 for every invocation in the current shell session
-export OPENAPI_GENERATOR_VERSION=3.0.2
-openapi-generator-cli version # is 3.0.2
-openapi-generator-cli version # is also 3.0.2
+# Execute version 4.0.2 for every invocation in the current shell session
+export OPENAPI_GENERATOR_VERSION=4.0.2
+openapi-generator-cli version # is 4.0.2
+openapi-generator-cli version # is also 4.0.2
# To "install" a specific version, set the variable in .bashrc/.bash_profile
-echo "export OPENAPI_GENERATOR_VERSION=3.0.2" >> ~/.bashrc
+echo "export OPENAPI_GENERATOR_VERSION=4.0.2" >> ~/.bashrc
source ~/.bashrc
-openapi-generator-cli version # is always 3.0.2, unless any of the above overrides are done ad hoc
+openapi-generator-cli version # is always 4.0.2, unless any of the above overrides are done ad hoc
```
### [1.4 - Build Projects](#table-of-contents)
@@ -577,6 +577,7 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
- [Adaptant Solutions AG](https://www.adaptant.io/)
- [adesso SE](https://www.adesso.de/)
- [Agoda](https://www.agoda.com/)
+- [Airthings](https://www.airthings.com/)
- [Allianz](https://www.allianz.com)
- [Angular.Schule](https://angular.schule/)
- [Aqovia](https://aqovia.com/)
@@ -843,6 +844,8 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
- 2021-10-02 - [How to Write Fewer Lines of Code with the OpenAPI Generator](https://hackernoon.com/how-to-write-fewer-lines-of-code-with-the-openapi-generator) by [Mikhail Alfa](https://hackernoon.com/u/alphamikle)
- 2021-10-12 - [OpenAPI Generator : 4000 étoiles sur GitHub et des spaghettis](https://www.youtube.com/watch?v=9hEsNBSqTFk) by [Jérémie Bresson](https://github.com/jmini) at [Devoxx FR 2021](https://cfp.devoxx.fr/2021/speaker/jeremie_bresson)
- 2021-10-17 - [Generate a TypeScript HTTP Client From An OpenAPI Spec In DotNET 5](https://richardwillis.info/blog/generate-a-type-script-http-client-from-an-open-api-spec-in-dot-net-5) by [Richard Willis](https://github.com/badsyntax)
+- 2021-11-06 - [スタートアップの開発で意識したこと](https://zenn.dev/woo_noo/articles/5cb09f8e2899ae782ad1) by [woo-noo](https://zenn.dev/woo_noo)
+- 2021-11-09 - [Effective Software Development using OpenAPI Generator](https://apexlabs.ai/post/effective-software-development-using-openapi-generator) by Ajil Oomme
## [6 - About Us](#table-of-contents)
@@ -951,6 +954,7 @@ Here is a list of template creators:
* C# ASP.NET 5: @jimschubert [:heart:](https://www.patreon.com/jimschubert)
* C# ASP.NET Core 3.0: @A-Joshi
* C# APS.NET Core 3.1: @phatcher
+ * C# Azure functions: @Abrhm7786
* C# NancyFX: @mstefaniuk
* C++ (Qt5 QHttpEngine): @etherealjoy
* C++ Pistache: @sebymiano
@@ -1059,7 +1063,7 @@ If you want to join the committee, please kindly apply by sending an email to te
| GraphQL | @renepardon (2018/12) |
| Groovy | |
| Haskell | |
-| Java | @bbdouglas (2017/07) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01) @karismann (2019/03) @Zomzog (2019/04) @lwlee2608 (2019/10) @nmuesch (2021/01) |
+| Java | @bbdouglas (2017/07) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01) @karismann (2019/03) @Zomzog (2019/04) @lwlee2608 (2019/10) |
| JMeter | @kannkyo (2021/01) |
| Kotlin | @jimschubert (2017/09) [:heart:](https://www.patreon.com/jimschubert), @dr4ke616 (2018/08) @karismann (2019/03) @Zomzog (2019/04) @andrewemery (2019/10) @4brunu (2019/11) @yutaka0m (2020/03) |
| Lua | @daurnimator (2017/08) |
diff --git a/bin/configs/java-okhttp-gson-nextgen.yaml b/bin/configs/java-okhttp-gson-nextgen.yaml
new file mode 100644
index 00000000000..b6b12f86bdd
--- /dev/null
+++ b/bin/configs/java-okhttp-gson-nextgen.yaml
@@ -0,0 +1,9 @@
+generatorName: java
+outputDir: samples/client/petstore/java/okhttp-gson-nextgen
+library: okhttp-gson-nextgen
+#inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml
+inputSpec: modules/openapi-generator/src/test/resources/3_0/java/petstore-with-fake-endpoints-models-for-testing-with-http-signature-okhttp-gson.yaml
+templateDir: modules/openapi-generator/src/main/resources/Java
+additionalProperties:
+ artifactId: petstore-okhttp-gson-nextgen
+ hideGenerationTimestamp: "true"
diff --git a/bin/configs/other/csharp-netcore-functions.yaml b/bin/configs/other/csharp-netcore-functions.yaml
new file mode 100644
index 00000000000..6d7e9a691b0
--- /dev/null
+++ b/bin/configs/other/csharp-netcore-functions.yaml
@@ -0,0 +1,6 @@
+generatorName: csharp-netcore-functions
+outputDir: samples/client/petstore/csharp-netcore-functions
+inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
+templateDir: modules/openapi-generator/src/main/resources/csharp-netcore-functions
+#additionalProperties:
+# packageGuid: '{321C8C3F-0156-40C1-AE42-D59761FB9B6C}'
diff --git a/bin/configs/swift5-frozenEnums.yaml b/bin/configs/swift5-frozenEnums.yaml
new file mode 100644
index 00000000000..64dc04a4f81
--- /dev/null
+++ b/bin/configs/swift5-frozenEnums.yaml
@@ -0,0 +1,12 @@
+generatorName: swift5
+outputDir: samples/client/petstore/swift5/frozenEnums
+inputSpec: modules/openapi-generator/src/test/resources/2_0/swift/petstore-with-fake-endpoints-models-for-testing.yaml
+templateDir: modules/openapi-generator/src/main/resources/swift5
+generateAliasAsModel: true
+additionalProperties:
+ podAuthors: ""
+ podSummary: PetstoreClient
+ sortParamsByRequiredFlag: false
+ generateFrozenEnums: false
+ projectName: PetstoreClient
+ podHomepage: https://github.com/openapitools/openapi-generator
diff --git a/bin/configs/typescript-angular-v13-provided-in-root-with-npm.yaml b/bin/configs/typescript-angular-v13-provided-in-root-with-npm.yaml
new file mode 100644
index 00000000000..22284f92f6c
--- /dev/null
+++ b/bin/configs/typescript-angular-v13-provided-in-root-with-npm.yaml
@@ -0,0 +1,11 @@
+generatorName: typescript-angular
+outputDir: samples/client/petstore/typescript-angular-v13-provided-in-root/builds/with-npm
+inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
+templateDir: modules/openapi-generator/src/main/resources/typescript-angular
+additionalProperties:
+ ngVersion: 13.0.1
+ npmVersion: 1.0.0
+ npmName: '@openapitools/typescript-angular-petstore'
+ npmRepository: https://skimdb.npmjs.com/registry
+ snapshot: false
+ supportsES6: true
diff --git a/bin/configs/typescript-angular-v13-provided-in-root.yaml b/bin/configs/typescript-angular-v13-provided-in-root.yaml
new file mode 100644
index 00000000000..bf16e022ded
--- /dev/null
+++ b/bin/configs/typescript-angular-v13-provided-in-root.yaml
@@ -0,0 +1,7 @@
+generatorName: typescript-angular
+outputDir: samples/client/petstore/typescript-angular-v13-provided-in-root/builds/default
+inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
+templateDir: modules/openapi-generator/src/main/resources/typescript-angular
+additionalProperties:
+ ngVersion: 13.0.1
+ supportsES6: true
diff --git a/docs/generators.md b/docs/generators.md
index ed80e860e49..6ce82ffadbb 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -86,6 +86,7 @@ The following generators are available:
* [cpp-qt-qhttpengine-server](generators/cpp-qt-qhttpengine-server.md)
* [cpp-restbed-server](generators/cpp-restbed-server.md)
* [csharp-nancyfx](generators/csharp-nancyfx.md)
+* [csharp-netcore-functions (beta)](generators/csharp-netcore-functions.md)
* [erlang-server](generators/erlang-server.md)
* [fsharp-functions (beta)](generators/fsharp-functions.md)
* [fsharp-giraffe-server (beta)](generators/fsharp-giraffe-server.md)
diff --git a/docs/generators/crystal.md b/docs/generators/crystal.md
index 721384c810c..93a893215ca 100644
--- a/docs/generators/crystal.md
+++ b/docs/generators/crystal.md
@@ -58,6 +58,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
abstract
alias
+annotation
as
as?
asm
diff --git a/docs/generators/csharp-netcore-functions.md b/docs/generators/csharp-netcore-functions.md
new file mode 100644
index 00000000000..50ec49b34a1
--- /dev/null
+++ b/docs/generators/csharp-netcore-functions.md
@@ -0,0 +1,300 @@
+---
+title: Config Options for csharp-netcore-functions
+sidebar_label: csharp-netcore-functions
+---
+
+These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
+
+| Option | Description | Values | Default |
+| ------ | ----------- | ------ | ------- |
+|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
+|caseInsensitiveResponseHeaders|Make API response's headers case-insensitive| |false|
+|conditionalSerialization|Serialize only those properties which are initialized by user, accepted values are true or false, default value is false.| |false|
+|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|**false** The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. **true** Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default. |true|
+|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
+|interfacePrefix|Prefix interfaces with a community standard or widely accepted prefix.| |I|
+|library|HTTP library template (sub-template) to use|**httpclient** HttpClient (https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient) (Experimental. May subject to breaking changes without further notice.) **restsharp** RestSharp (https://github.com/restsharp/RestSharp) |restsharp|
+|licenseId|The identifier of the license| |null|
+|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name| |PascalCase|
+|netCoreProjectFile|Use the new format (.NET Core) for .NET project files (.csproj).| |false|
+|nonPublicApi|Generates code with reduced access modifiers; allows embedding elsewhere without exposing non-public API calls to consumers.| |false|
+|nullableReferenceTypes|Use nullable annotations in the project. Only supported on C# 8 / ASP.NET Core 3.0 or newer.| |false|
+|optionalAssemblyInfo|Generate AssemblyInfo.cs.| |true|
+|optionalEmitDefaultValues|Set DataMember's EmitDefaultValue.| |false|
+|optionalMethodArgument|C# Optional method argument, e.g. void square(int x=10) (.net 4.0+ only).| |true|
+|optionalProjectFile|Generate {PackageName}.csproj.| |true|
+|packageGuid|The GUID that will be associated with the C# project| |null|
+|packageName|C# package name (convention: Title.Case).| |Org.OpenAPITools|
+|packageTags|Tags to identify the package| |null|
+|packageVersion|C# package version.| |1.0.0|
+|releaseNote|Release note, default to 'Minor update'.| |Minor update|
+|returnICollection|Return ICollection<T> instead of the concrete type.| |false|
+|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
+|sourceFolder|source folder for generated code| |src|
+|targetFramework|The target .NET framework version. To target multiple frameworks, use `;` as the separator, e.g. `netstandard2.1;netcoreapp3.0`|**netstandard1.3** .NET Standard 1.3 compatible **netstandard1.4** .NET Standard 1.4 compatible **netstandard1.5** .NET Standard 1.5 compatible **netstandard1.6** .NET Standard 1.6 compatible **netstandard2.0** .NET Standard 2.0 compatible **netstandard2.1** .NET Standard 2.1 compatible **netcoreapp2.0** .NET Core 2.0 compatible **netcoreapp2.1** .NET Core 2.1 compatible **netcoreapp3.0** .NET Core 3.0 compatible **netcoreapp3.1** .NET Core 3.1 compatible **net47** .NET Framework 4.7 compatible **net5.0** .NET 5.0 compatible |netstandard2.0|
+|useCollection|Deserialize array types to Collection<T> instead of List<T>.| |false|
+|useDateTimeOffset|Use DateTimeOffset to model date-time properties| |false|
+|useOneOfDiscriminatorLookup|Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped.| |false|
+|validatable|Generates self-validatable models.| |true|
+
+## IMPORT MAPPING
+
+| Type/Alias | Imports |
+| ---------- | ------- |
+
+
+## INSTANTIATION TYPES
+
+| Type/Alias | Instantiated By |
+| ---------- | --------------- |
+|array|List|
+|list|List|
+|map|Dictionary|
+
+
+## LANGUAGE PRIMITIVES
+
+
+Boolean
+Collection
+DateTime
+DateTime?
+DateTimeOffset
+DateTimeOffset?
+Decimal
+Dictionary
+Double
+Float
+Guid
+Guid?
+ICollection
+Int32
+Int64
+List
+Object
+String
+System.IO.Stream
+bool
+bool?
+byte[]
+decimal
+decimal?
+double
+double?
+float
+float?
+int
+int?
+long
+long?
+string
+
+
+## RESERVED WORDS
+
+
+Client
+Configuration
+Version
+abstract
+as
+base
+bool
+break
+byte
+case
+catch
+char
+checked
+class
+client
+const
+continue
+decimal
+default
+delegate
+do
+double
+else
+enum
+event
+explicit
+extern
+false
+finally
+fixed
+float
+for
+foreach
+goto
+if
+implicit
+in
+int
+interface
+internal
+is
+localVarFileParams
+localVarFormParams
+localVarHeaderParams
+localVarHttpContentType
+localVarHttpContentTypes
+localVarHttpHeaderAccept
+localVarHttpHeaderAccepts
+localVarPath
+localVarPathParams
+localVarPostBody
+localVarQueryParams
+localVarResponse
+localVarStatusCode
+lock
+long
+namespace
+new
+null
+object
+operator
+out
+override
+parameter
+params
+private
+protected
+public
+readonly
+ref
+return
+sbyte
+sealed
+short
+sizeof
+stackalloc
+static
+string
+struct
+switch
+this
+throw
+true
+try
+typeof
+uint
+ulong
+unchecked
+unsafe
+ushort
+using
+virtual
+void
+volatile
+while
+
+
+## FEATURE SET
+
+
+### Client Modification Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasePath|✓|ToolingExtension
+|Authorizations|✗|ToolingExtension
+|UserAgent|✓|ToolingExtension
+|MockServer|✗|ToolingExtension
+
+### Data Type Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Custom|✗|OAS2,OAS3
+|Int32|✓|OAS2,OAS3
+|Int64|✓|OAS2,OAS3
+|Float|✓|OAS2,OAS3
+|Double|✓|OAS2,OAS3
+|Decimal|✓|ToolingExtension
+|String|✓|OAS2,OAS3
+|Byte|✓|OAS2,OAS3
+|Binary|✓|OAS2,OAS3
+|Boolean|✓|OAS2,OAS3
+|Date|✓|OAS2,OAS3
+|DateTime|✓|OAS2,OAS3
+|Password|✓|OAS2,OAS3
+|File|✓|OAS2
+|Array|✓|OAS2,OAS3
+|Maps|✓|ToolingExtension
+|CollectionFormat|✓|OAS2
+|CollectionFormatMulti|✓|OAS2
+|Enum|✓|OAS2,OAS3
+|ArrayOfEnum|✓|ToolingExtension
+|ArrayOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
+|ArrayOfCollectionOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfEnum|✓|ToolingExtension
+|MapOfEnum|✓|ToolingExtension
+|MapOfModel|✓|ToolingExtension
+|MapOfCollectionOfPrimitives|✓|ToolingExtension
+|MapOfCollectionOfModel|✓|ToolingExtension
+|MapOfCollectionOfEnum|✓|ToolingExtension
+
+### Documentation Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Readme|✓|ToolingExtension
+|Model|✓|ToolingExtension
+|Api|✓|ToolingExtension
+
+### Global Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Host|✓|OAS2,OAS3
+|BasePath|✓|OAS2,OAS3
+|Info|✓|OAS2,OAS3
+|Schemes|✗|OAS2,OAS3
+|PartialSchemes|✓|OAS2,OAS3
+|Consumes|✓|OAS2
+|Produces|✓|OAS2
+|ExternalDocumentation|✓|OAS2,OAS3
+|Examples|✓|OAS2,OAS3
+|XMLStructureDefinitions|✗|OAS2,OAS3
+|MultiServer|✗|OAS3
+|ParameterizedServer|✗|OAS3
+|ParameterStyling|✗|OAS3
+|Callbacks|✗|OAS3
+|LinkObjects|✗|OAS3
+
+### Parameter Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Path|✓|OAS2,OAS3
+|Query|✓|OAS2,OAS3
+|Header|✓|OAS2,OAS3
+|Body|✓|OAS2
+|FormUnencoded|✓|OAS2
+|FormMultipart|✓|OAS2
+|Cookie|✓|OAS3
+
+### Schema Support Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Simple|✓|OAS2,OAS3
+|Composite|✓|OAS2,OAS3
+|Polymorphism|✓|OAS2,OAS3
+|Union|✗|OAS3
+
+### Security Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasicAuth|✓|OAS2,OAS3
+|ApiKey|✓|OAS2,OAS3
+|OpenIDConnect|✗|OAS3
+|BearerToken|✗|OAS3
+|OAuth2_Implicit|✓|OAS2,OAS3
+|OAuth2_Password|✗|OAS2,OAS3
+|OAuth2_ClientCredentials|✗|OAS2,OAS3
+|OAuth2_AuthorizationCode|✗|OAS2,OAS3
+
+### Wire Format Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|JSON|✓|OAS2,OAS3
+|XML|✓|OAS2,OAS3
+|PROTOBUF|✗|ToolingExtension
+|Custom|✗|OAS2,OAS3
diff --git a/docs/generators/csharp-netcore.md b/docs/generators/csharp-netcore.md
index 7a30e18f899..bb138ef414d 100644
--- a/docs/generators/csharp-netcore.md
+++ b/docs/generators/csharp-netcore.md
@@ -31,7 +31,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|returnICollection|Return ICollection<T> instead of the concrete type.| |false|
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|sourceFolder|source folder for generated code| |src|
-|targetFramework|The target .NET framework version. To target multiple frameworks, use `;` as the separator, e.g. `netstandard2.1;netcoreapp3.0`|**netstandard1.3** .NET Standard 1.3 compatible **netstandard1.4** .NET Standard 1.4 compatible **netstandard1.5** .NET Standard 1.5 compatible **netstandard1.6** .NET Standard 1.6 compatible **netstandard2.0** .NET Standard 2.0 compatible **netstandard2.1** .NET Standard 2.1 compatible **netcoreapp2.0** .NET Core 2.0 compatible **netcoreapp2.1** .NET Core 2.1 compatible **netcoreapp3.0** .NET Core 3.0 compatible **netcoreapp3.1** .NET Core 3.1 compatible **net47** .NET Framework 4.7 compatible **net5.0** .NET 5.0 compatible |netstandard2.0|
+|targetFramework|The target .NET framework version. To target multiple frameworks, use `;` as the separator, e.g. `netstandard2.1;netcoreapp3.0`|**netstandard1.3** .NET Standard 1.3 compatible **netstandard1.4** .NET Standard 1.4 compatible **netstandard1.5** .NET Standard 1.5 compatible **netstandard1.6** .NET Standard 1.6 compatible **netstandard2.0** .NET Standard 2.0 compatible **netstandard2.1** .NET Standard 2.1 compatible **netcoreapp2.0** .NET Core 2.0 compatible **netcoreapp2.1** .NET Core 2.1 compatible **netcoreapp3.0** .NET Core 3.0 compatible **netcoreapp3.1** .NET Core 3.1 compatible **net47** .NET Framework 4.7 compatible **net5.0** .NET 5.0 compatible **net6.0** .NET 6.0 compatible |netstandard2.0|
|useCollection|Deserialize array types to Collection<T> instead of List<T>.| |false|
|useDateTimeOffset|Use DateTimeOffset to model date-time properties| |false|
|useOneOfDiscriminatorLookup|Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped.| |false|
diff --git a/docs/generators/java.md b/docs/generators/java.md
index 8b360b4b427..1160c36f8b9 100644
--- a/docs/generators/java.md
+++ b/docs/generators/java.md
@@ -38,7 +38,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|invokerPackage|root package for generated code| |org.openapitools.client|
|java8|Use Java8 classes instead of third party equivalents. Starting in 5.x, JDK8 is the default and the support for JDK7, JDK6 has been dropped|**true** Use Java 8 classes such as Base64 **false** Various third party libraries as needed |true|
|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).|**true** The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document. **false** The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing. |true|
-|library|library template (sub-template) to use|**jersey1** HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.x. Enable gzip request encoding using '-DuseGzipFeature=true'. IMPORTANT NOTE: jersey 1.x is no longer actively maintained so please upgrade to 'jersey2' or other HTTP libraries instead. **jersey2** HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.9.x **feign** HTTP client: OpenFeign 10.x. JSON processing: Jackson 2.9.x. **okhttp-gson** [DEFAULT] HTTP client: OkHttp 3.x. JSON processing: Gson 2.8.x. Enable Parcelable models on Android using '-DparcelableModel=true'. Enable gzip request encoding using '-DuseGzipFeature=true'. **retrofit2** HTTP client: OkHttp 3.x. JSON processing: Gson 2.x (Retrofit 2.3.0). Enable the RxJava adapter using '-DuseRxJava[2/3]=true'. (RxJava 1.x or 2.x or 3.x) **resttemplate** HTTP client: Spring RestTemplate 4.x. JSON processing: Jackson 2.9.x **webclient** HTTP client: Spring WebClient 5.x. JSON processing: Jackson 2.9.x **resteasy** HTTP client: Resteasy client 3.x. JSON processing: Jackson 2.9.x **vertx** HTTP client: VertX client 3.x. JSON processing: Jackson 2.9.x **google-api-client** HTTP client: Google API client 1.x. JSON processing: Jackson 2.9.x **rest-assured** HTTP client: rest-assured : 4.x. JSON processing: Gson 2.x or Jackson 2.10.x. Only for Java 8 **native** HTTP client: Java native HttpClient. JSON processing: Jackson 2.9.x. Only for Java11+ **microprofile** HTTP client: Microprofile client 1.x. JSON processing: JSON-B **apache-httpclient** HTTP client: Apache httpclient 4.x |okhttp-gson|
+|library|library template (sub-template) to use|**jersey1** HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.x. Enable gzip request encoding using '-DuseGzipFeature=true'. IMPORTANT NOTE: jersey 1.x is no longer actively maintained so please upgrade to 'jersey2' or other HTTP libraries instead. **jersey2** HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.9.x **feign** HTTP client: OpenFeign 10.x. JSON processing: Jackson 2.9.x. **okhttp-gson** [DEFAULT] HTTP client: OkHttp 3.x. JSON processing: Gson 2.8.x. Enable Parcelable models on Android using '-DparcelableModel=true'. Enable gzip request encoding using '-DuseGzipFeature=true'. **okhttp-gson-nextgen** HTTP client: OkHttp 3.x. JSON processing: Gson 2.8.x.'. Better support for oneOf/anyOf with breaking changes. Will replace `okhttp-gson` in the 6.0.0 release. **retrofit2** HTTP client: OkHttp 3.x. JSON processing: Gson 2.x (Retrofit 2.3.0). Enable the RxJava adapter using '-DuseRxJava[2/3]=true'. (RxJava 1.x or 2.x or 3.x) **resttemplate** HTTP client: Spring RestTemplate 4.x. JSON processing: Jackson 2.9.x **webclient** HTTP client: Spring WebClient 5.x. JSON processing: Jackson 2.9.x **resteasy** HTTP client: Resteasy client 3.x. JSON processing: Jackson 2.9.x **vertx** HTTP client: VertX client 3.x. JSON processing: Jackson 2.9.x **google-api-client** HTTP client: Google API client 1.x. JSON processing: Jackson 2.9.x **rest-assured** HTTP client: rest-assured : 4.x. JSON processing: Gson 2.x or Jackson 2.10.x. Only for Java 8 **native** HTTP client: Java native HttpClient. JSON processing: Jackson 2.9.x. Only for Java11+ **microprofile** HTTP client: Microprofile client 1.x. JSON processing: JSON-B **apache-httpclient** HTTP client: Apache httpclient 4.x |okhttp-gson|
|licenseName|The name of the license| |Unlicense|
|licenseUrl|The URL of the license| |http://unlicense.org|
|microprofileFramework|Framework for microprofile. Possible values "kumuluzee"| |null|
diff --git a/docs/generators/kotlin.md b/docs/generators/kotlin.md
index fca84164c69..49e02994b74 100644
--- a/docs/generators/kotlin.md
+++ b/docs/generators/kotlin.md
@@ -17,6 +17,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|library|Library template (sub-template) to use|**jvm-okhttp4** [DEFAULT] Platform: Java Virtual Machine. HTTP client: OkHttp 4.2.0 (Android 5.0+ and Java 8+). JSON processing: Moshi 1.8.0. **jvm-okhttp3** Platform: Java Virtual Machine. HTTP client: OkHttp 3.12.4 (Android 2.3+ and Java 7+). JSON processing: Moshi 1.8.0. **jvm-retrofit2** Platform: Java Virtual Machine. HTTP client: Retrofit 2.6.2. **multiplatform** Platform: Kotlin multiplatform. HTTP client: Ktor 1.6.0. JSON processing: Kotlinx Serialization: 1.2.1. |jvm-okhttp4|
|modelMutable|Create mutable models| |false|
|moshiCodeGen|Whether to enable codegen with the Moshi library. Refer to the [official Moshi doc](https://github.com/square/moshi#codegen) for more info.| |false|
+|omitGradlePluginVersions|Whether to declare Gradle plugin versions in build files.| |false|
|packageName|Generated artifact package name.| |org.openapitools.client|
|parcelizeModels|toggle "@Parcelize" for generated models| |null|
|requestDateConverter|JVM-Option. Defines in how to handle date-time objects that are used for a request (as query or parameter)|**toJson** [DEFAULT] Date formatter option using a json converter. **toString** Use the 'toString'-method of the date-time object to retrieve the related string representation. |toJson|
diff --git a/docs/generators/protobuf-schema.md b/docs/generators/protobuf-schema.md
index 104a47fe59c..a7d1f1d095b 100644
--- a/docs/generators/protobuf-schema.md
+++ b/docs/generators/protobuf-schema.md
@@ -7,6 +7,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
+|numberedFieldNumberList|Field numbers in order.| |false|
+|startEnumsWithUnknown|Introduces "UNKNOWN" as the first element of enumerations.| |false|
## IMPORT MAPPING
diff --git a/docs/generators/ruby.md b/docs/generators/ruby.md
index c9e0477e967..5cd52c8c27a 100644
--- a/docs/generators/ruby.md
+++ b/docs/generators/ruby.md
@@ -10,13 +10,13 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|**false** The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. **true** Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default. |true|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
-|gemAuthor|gem author (only one is supported).| |null|
+|gemAuthor|gem author (only one is supported).| |OpenAPI-Generator|
|gemAuthorEmail|gem author email (only one is supported).| |null|
|gemDescription|gem description. | |This gem maps to a REST API|
-|gemHomepage|gem homepage. | |http://org.openapitools|
+|gemHomepage|gem homepage. | |https://openapi-generator.tech|
|gemLicense|gem license. | |unlicense|
|gemName|gem name (convention: underscore_case).| |openapi_client|
-|gemRequiredRubyVersion|gem required Ruby version. | |>= 1.9|
+|gemRequiredRubyVersion|gem required Ruby version. | |>= 2.4|
|gemSummary|gem summary. | |A ruby wrapper for the REST APIs|
|gemVersion|gem version.| |1.0.0|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
diff --git a/docs/generators/swift5.md b/docs/generators/swift5.md
index e74a239be25..9404a2fd458 100644
--- a/docs/generators/swift5.md
+++ b/docs/generators/swift5.md
@@ -11,6 +11,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|apiNamePrefix|Prefix that will be appended to all API names ('tags'). Default: empty string. e.g. Pet => Pet.| |null|
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|**false** The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. **true** Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default. |true|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
+|generateFrozenEnums|Generate frozen enums (default: true)| |true|
|generateModelAdditionalProperties|Generate model additional properties (default: true)| |true|
|hashableModels|Make hashable models (default: true)| |true|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
diff --git a/docs/generators/typescript-angular.md b/docs/generators/typescript-angular.md
index ab8b3da35fc..2083b09cadf 100644
--- a/docs/generators/typescript-angular.md
+++ b/docs/generators/typescript-angular.md
@@ -19,7 +19,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|modelFileSuffix|The suffix of the file of the generated model (model<suffix>.ts).| |null|
|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name. Only change it if you provide your own run-time code for (de-)serialization of models| |original|
|modelSuffix|The suffix of the generated model.| |null|
-|ngVersion|The version of Angular. (At least 6.0.0)| |12.2.12|
+|ngVersion|The version of Angular. (At least 6.0.0)| |13.0.1|
|npmName|The name under which you want to publish generated npm package. Required to generate a full package| |null|
|npmRepository|Use this property to set an url your private npmRepo in the package.json| |null|
|npmVersion|The version of your npm package. If not provided, using the version from the OpenAPI specification file.| |1.0.0|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenEncoding.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenEncoding.java
new file mode 100644
index 00000000000..efd5b0f16ab
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenEncoding.java
@@ -0,0 +1,67 @@
+package org.openapitools.codegen;
+
+import java.util.List;
+import java.util.Objects;
+
+public class CodegenEncoding {
+ private String contentType;
+ private List headers;
+ private String style;
+ private boolean explode;
+ private boolean allowReserved;
+
+ public CodegenEncoding(String contentType, List headers, String style, boolean explode, boolean allowReserved) {
+ this.contentType = contentType;
+ this.headers = headers;
+ this.style = style;
+ this.explode = explode;
+ this.allowReserved = allowReserved;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public List getHeaders() {
+ return headers;
+ }
+
+ public String getStyle() {
+ return style;
+ }
+
+ public boolean getExplode() {
+ return explode;
+ }
+
+ public boolean getAllowReserved() {
+ return allowReserved;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("CodegenEncoding{");
+ sb.append("contentType=").append(contentType);
+ sb.append(", headers=").append(headers);
+ sb.append(", style=").append(style);
+ sb.append(", explode=").append(explode);
+ sb.append(", allowReserved=").append(allowReserved);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CodegenEncoding that = (CodegenEncoding) o;
+ return contentType == that.getContentType() &&
+ Objects.equals(headers, that.getHeaders()) &&
+ style == that.getStyle() &&
+ explode == that.getExplode() &&
+ allowReserved == that.getAllowReserved();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(contentType, headers, style, explode, allowReserved);
+ }
+}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenMediaType.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenMediaType.java
new file mode 100644
index 00000000000..965e5031942
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenMediaType.java
@@ -0,0 +1,45 @@
+package org.openapitools.codegen;
+
+import java.util.LinkedHashMap;
+import java.util.Objects;
+
+public class CodegenMediaType {
+ private CodegenProperty schema;
+ private LinkedHashMap encoding;
+
+ public CodegenMediaType(CodegenProperty schema, LinkedHashMap encoding) {
+ this.schema = schema;
+ this.encoding = encoding;
+ }
+
+ public CodegenProperty getSchema() {
+ return schema;
+ }
+
+ public LinkedHashMap getEncoding() {
+ return encoding;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("CodegenMediaType{");
+ sb.append("schema=").append(schema);
+ sb.append(", encoding=").append(encoding);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CodegenMediaType that = (CodegenMediaType) o;
+ return Objects.equals(schema,that.getSchema()) &&
+ Objects.equals(encoding, that.getEncoding());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schema, encoding);
+ }
+}
+
+
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenOperation.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenOperation.java
index ef348bbb266..83413a9ee11 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenOperation.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenOperation.java
@@ -29,7 +29,8 @@ public class CodegenOperation {
isArray, isMultipart,
isResponseBinary = false, isResponseFile = false, hasReference = false,
isRestfulIndex, isRestfulShow, isRestfulCreate, isRestfulUpdate, isRestfulDestroy,
- isRestful, isDeprecated, isCallbackRequest, uniqueItems, hasDefaultResponse = false;
+ isRestful, isDeprecated, isCallbackRequest, uniqueItems, hasDefaultResponse = false,
+ hasErrorResponseObject; // if 4xx, 5xx repsonses have at least one error object defined
public String path, operationId, returnType, returnFormat, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse;
public CodegenDiscriminator discriminator;
@@ -297,6 +298,7 @@ public class CodegenOperation {
sb.append(", isResponseFile=").append(isResponseFile);
sb.append(", hasReference=").append(hasReference);
sb.append(", hasDefaultResponse=").append(hasDefaultResponse);
+ sb.append(", hasErrorResponseObject=").append(hasErrorResponseObject);
sb.append(", isRestfulIndex=").append(isRestfulIndex);
sb.append(", isRestfulShow=").append(isRestfulShow);
sb.append(", isRestfulCreate=").append(isRestfulCreate);
@@ -371,6 +373,7 @@ public class CodegenOperation {
isResponseFile == that.isResponseFile &&
hasReference == that.hasReference &&
hasDefaultResponse == that.hasDefaultResponse &&
+ hasErrorResponseObject == that.hasErrorResponseObject &&
isRestfulIndex == that.isRestfulIndex &&
isRestfulShow == that.isRestfulShow &&
isRestfulCreate == that.isRestfulCreate &&
@@ -435,6 +438,7 @@ public class CodegenOperation {
produces, prioritizedContentTypes, servers, bodyParam, allParams, bodyParams, pathParams, queryParams,
headerParams, formParams, cookieParams, requiredParams, optionalParams, authMethods, tags,
responses, callbacks, imports, examples, requestBodyExamples, externalDocs, vendorExtensions,
- nickname, operationIdOriginal, operationIdLowerCase, operationIdCamelCase, operationIdSnakeCase);
+ nickname, operationIdOriginal, operationIdLowerCase, operationIdCamelCase, operationIdSnakeCase,
+ hasErrorResponseObject);
}
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java
index 38eb785410e..dba1721fbca 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java
@@ -52,6 +52,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
public boolean hasValidation;
public boolean isNullable;
public boolean isDeprecated;
+ private CodegenProperty schema;
/**
* Determines whether this parameter is mandatory. If the parameter is in "path",
* this property is required and its value MUST be true. Otherwise, the property
@@ -109,6 +110,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
private boolean hasDiscriminatorWithNonEmptyMapping;
private CodegenComposedSchemas composedSchemas;
private boolean hasMultipleTypes = false;
+ private LinkedHashMap content;
public CodegenParameter copy() {
CodegenParameter output = new CodegenParameter();
@@ -162,6 +164,12 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
output.setHasDiscriminatorWithNonEmptyMapping(this.hasDiscriminatorWithNonEmptyMapping);
output.setHasMultipleTypes(this.hasMultipleTypes);
+ if (this.content != null) {
+ output.setContent(this.content);
+ }
+ if (this.schema != null) {
+ output.setSchema(this.schema);
+ }
if (this.composedSchemas != null) {
output.setComposedSchemas(this.getComposedSchemas());
}
@@ -222,7 +230,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
@Override
public int hashCode() {
- return Objects.hash(isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam, isBodyParam, isContainer, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName, paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, style, isDeepObject, isAllowEmptyValue, example, jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isFreeFormObject, isAnyType, isArray, isMap, isFile, isEnum, _enum, allowableValues, items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable, isDeprecated, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull, additionalPropertiesIsAnyType, hasVars, hasRequired, isShort, isUnboundedInteger, hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes);
+ return Objects.hash(isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam, isBodyParam, isContainer, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName, paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, style, isDeepObject, isAllowEmptyValue, example, jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isFreeFormObject, isAnyType, isArray, isMap, isFile, isEnum, _enum, allowableValues, items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable, isDeprecated, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull, additionalPropertiesIsAnyType, hasVars, hasRequired, isShort, isUnboundedInteger, hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema, content);
}
@Override
@@ -278,6 +286,8 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
getExclusiveMaximum() == that.getExclusiveMaximum() &&
getExclusiveMinimum() == that.getExclusiveMinimum() &&
getUniqueItems() == that.getUniqueItems() &&
+ Objects.equals(content, that.getContent()) &&
+ Objects.equals(schema, that.getSchema()) &&
Objects.equals(composedSchemas, that.getComposedSchemas()) &&
Objects.equals(baseName, that.baseName) &&
Objects.equals(paramName, that.paramName) &&
@@ -403,6 +413,8 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
sb.append(", getHasDiscriminatorWithNonEmptyMapping=").append(hasDiscriminatorWithNonEmptyMapping);
sb.append(", composedSchemas=").append(composedSchemas);
sb.append(", hasMultipleTypes=").append(hasMultipleTypes);
+ sb.append(", schema=").append(schema);
+ sb.append(", content=").append(content);
sb.append('}');
return sb.toString();
}
@@ -732,5 +744,17 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
@Override
public void setHasMultipleTypes(boolean hasMultipleTypes) { this.hasMultipleTypes = hasMultipleTypes; }
+
+ public CodegenProperty getSchema() {return schema; }
+
+ public void setSchema(CodegenProperty schema) { this.schema = schema; }
+
+ public LinkedHashMap getContent() {
+ return content;
+ }
+
+ public void setContent(LinkedHashMap content) {
+ this.content = content;
+ }
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
index 6e669ab37cd..e97a6caf557 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
@@ -570,14 +570,7 @@ public class DefaultCodegen implements CodegenConfig {
List> models = (List>) inner.get("models");
for (Map mo : models) {
CodegenModel cm = (CodegenModel) mo.get("model");
- for (CodegenProperty cp : cm.allVars) {
- // detect self import
- if (cp.dataType.equalsIgnoreCase(cm.classname) ||
- (cp.isContainer && cp.items != null && cp.items.dataType.equalsIgnoreCase(cm.classname))) {
- cm.imports.remove(cm.classname); // remove self import
- cp.isSelfReference = true;
- }
- }
+ removeSelfReferenceImports(cm);
}
}
setCircularReferences(allModels);
@@ -585,6 +578,23 @@ public class DefaultCodegen implements CodegenConfig {
return objs;
}
+ /**
+ * Removes imports from the model that points to itself
+ * Marks a self referencing property, if detected
+ *
+ * @param model Self imports will be removed from this model.imports collection
+ */
+ protected void removeSelfReferenceImports(CodegenModel model) {
+ for (CodegenProperty cp : model.allVars) {
+ // detect self import
+ if (cp.dataType.equalsIgnoreCase(model.classname) ||
+ (cp.isContainer && cp.items != null && cp.items.dataType.equalsIgnoreCase(model.classname))) {
+ model.imports.remove(model.classname); // remove self import
+ cp.isSelfReference = true;
+ }
+ }
+ }
+
public void setCircularReferences(Map models) {
final Map> dependencyMap = models.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> getModelDependencies(entry.getValue())));
@@ -3966,6 +3976,12 @@ public class DefaultCodegen implements CodegenConfig {
if (Boolean.TRUE.equals(r.isFile) && Boolean.TRUE.equals(r.is2xx) && Boolean.FALSE.equals(op.isResponseFile)) {
op.isResponseFile = Boolean.TRUE;
}
+
+ // check if any 4xx or 5xx reponse has an error response object defined
+ if ((Boolean.TRUE.equals(r.is4xx) || Boolean.TRUE.equals(r.is5xx)) &&
+ Boolean.FALSE.equals(r.primitiveType) && Boolean.FALSE.equals(r.simpleType)) {
+ op.hasErrorResponseObject = Boolean.TRUE;
+ }
}
op.responses.sort((a, b) -> {
int aScore = a.isWildcard() ? 2 : a.isRange() ? 1 : 0;
@@ -4259,6 +4275,7 @@ public class DefaultCodegen implements CodegenConfig {
r.setComposedSchemas(getComposedSchemas(responseSchema));
if (ModelUtils.isArraySchema(responseSchema)) {
r.simpleType = false;
+ r.isArray = true;
r.containerType = cp.containerType;
ArraySchema as = (ArraySchema) responseSchema;
CodegenProperty items = fromProperty("response", getSchemaItems(as));
@@ -4314,6 +4331,8 @@ public class DefaultCodegen implements CodegenConfig {
} else if (ModelUtils.isTypeObjectSchema(responseSchema)) {
if (ModelUtils.isFreeFormObject(openAPI, responseSchema)) {
r.isFreeFormObject = true;
+ } else {
+ r.isModel = true;
}
r.simpleType = false;
r.containerType = cp.containerType;
@@ -4325,9 +4344,6 @@ public class DefaultCodegen implements CodegenConfig {
LOGGER.debug("Property type is not primitive: {}", cp.dataType);
}
- if (!r.isMap && !r.isArray) {
- r.simpleType = true;
- }
r.primitiveType = (r.baseType == null || languageSpecificPrimitives().contains(r.baseType));
if (r.baseType == null) {
@@ -4486,6 +4502,7 @@ public class DefaultCodegen implements CodegenConfig {
codegenParameter.isDeprecated = parameter.getDeprecated();
}
codegenParameter.jsonSchema = Json.pretty(parameter);
+ codegenParameter.setContent(getContent(parameter.getContent(), imports));
if (GlobalSettings.getProperty("debugParser") != null) {
LOGGER.info("working on Parameter {}", parameter.getName());
@@ -4499,6 +4516,8 @@ public class DefaultCodegen implements CodegenConfig {
Schema parameterSchema;
if (parameter.getSchema() != null) {
parameterSchema = parameter.getSchema();
+ CodegenProperty prop = fromProperty(parameter.getName(), parameterSchema);
+ codegenParameter.setSchema(prop);
} else if (parameter.getContent() != null) {
Content content = parameter.getContent();
if (content.size() > 1) {
@@ -4771,12 +4790,12 @@ public class DefaultCodegen implements CodegenConfig {
final CodegenSecurity cs = defaultCodegenSecurity(key, securityScheme);
cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isOAuth = false;
cs.isBasic = true;
- if ("basic".equals(securityScheme.getScheme())) {
+ if ("basic".equalsIgnoreCase(securityScheme.getScheme())) {
cs.isBasicBasic = true;
- } else if ("bearer".equals(securityScheme.getScheme())) {
+ } else if ("bearer".equalsIgnoreCase(securityScheme.getScheme())) {
cs.isBasicBearer = true;
cs.bearerFormat = securityScheme.getBearerFormat();
- } else if ("signature".equals(securityScheme.getScheme())) {
+ } else if ("signature".equalsIgnoreCase(securityScheme.getScheme())) {
// HTTP signature as defined in https://datatracker.ietf.org/doc/draft-cavage-http-signatures/
// The registry of security schemes is maintained by IANA.
// https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml
@@ -5165,17 +5184,7 @@ public class DefaultCodegen implements CodegenConfig {
cm.hasOnlyReadOnly = false;
}
- // TODO revise the logic to include map
- if (cp.isContainer) {
- addImport(cm, typeMapping.get("array"));
- }
-
- addImport(cm, cp.baseType);
- CodegenProperty innerCp = cp;
- while (innerCp != null) {
- addImport(cm, innerCp.complexType);
- innerCp = innerCp.items;
- }
+ addImportsForPropertyType(cm, cp);
// if required, add to the list "requiredVars"
if (Boolean.TRUE.equals(cp.required)) {
@@ -5196,6 +5205,28 @@ public class DefaultCodegen implements CodegenConfig {
return;
}
+ /**
+ * For a given property, adds all needed imports to the model
+ * This includes a flat property type (e.g. property type: ReferencedModel)
+ * as well as container type (property type: array of ReferencedModel's)
+ *
+ * @param model The codegen representation of the OAS schema.
+ * @param property The codegen representation of the OAS schema's property.
+ */
+ protected void addImportsForPropertyType(CodegenModel model, CodegenProperty property) {
+ // TODO revise the logic to include map
+ if (property.isContainer) {
+ addImport(model, typeMapping.get("array"));
+ }
+
+ addImport(model, property.baseType);
+ CodegenProperty innerCp = property;
+ while (innerCp != null) {
+ addImport(model, innerCp.complexType);
+ innerCp = innerCp.items;
+ }
+ }
+
/**
* Determine all of the types in the model definitions (schemas) that are aliases of
* simple types.
@@ -6555,6 +6586,65 @@ public class DefaultCodegen implements CodegenConfig {
codegenParameter.pattern = toRegularExpression(schema.getPattern());
}
+ protected String toMediaTypeSchemaName(String contentType) {
+ return toModelName(contentType + "Schema");
+ }
+
+ protected LinkedHashMap getContent(Content content, Set imports) {
+ if (content == null) {
+ return null;
+ }
+ LinkedHashMap cmtContent = new LinkedHashMap<>();
+ for (Entry contentEntry: content.entrySet()) {
+ MediaType mt = contentEntry.getValue();
+ LinkedHashMap ceMap = null;
+ if (mt.getEncoding() != null ) {
+ ceMap = new LinkedHashMap<>();
+ Map encMap = mt.getEncoding();
+ for (Entry encodingEntry: encMap.entrySet()) {
+ Encoding enc = encodingEntry.getValue();
+ List headers = new ArrayList<>();
+ if (enc.getHeaders() != null) {
+ Map encHeaders = enc.getHeaders();
+ for (Entry headerEntry: encHeaders.entrySet()) {
+ String headerName = headerEntry.getKey();
+ Header header = ModelUtils.getReferencedHeader(this.openAPI, headerEntry.getValue());
+ Parameter headerParam = new Parameter();
+ headerParam.setName(headerName);
+ headerParam.setIn("header");
+ headerParam.setDescription(header.getDescription());
+ headerParam.setRequired(header.getRequired());
+ headerParam.setDeprecated(header.getDeprecated());
+ headerParam.setStyle(Parameter.StyleEnum.valueOf(header.getStyle().name()));
+ headerParam.setExplode(header.getExplode());
+ headerParam.setSchema(header.getSchema());
+ headerParam.setExamples(header.getExamples());
+ headerParam.setExample(header.getExample());
+ headerParam.setContent(header.getContent());
+ headerParam.setExtensions(header.getExtensions());
+ CodegenParameter param = fromParameter(headerParam, imports);
+ headers.add(param);
+ }
+ }
+ CodegenEncoding ce = new CodegenEncoding(
+ enc.getContentType(),
+ headers,
+ enc.getStyle().toString(),
+ enc.getExplode().booleanValue(),
+ enc.getAllowReserved().booleanValue()
+ );
+ String propName = encodingEntry.getKey();
+ ceMap.put(propName, ce);
+ }
+ }
+ String contentType = contentEntry.getKey();
+ CodegenProperty schemaProp = fromProperty(toMediaTypeSchemaName(contentType), mt.getSchema());
+ CodegenMediaType codegenMt = new CodegenMediaType(schemaProp, ceMap);
+ cmtContent.put(contentType, codegenMt);
+ }
+ return cmtContent;
+ }
+
public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) {
if (body == null) {
LOGGER.error("body in fromRequestBody cannot be null!");
@@ -6576,6 +6666,7 @@ public class DefaultCodegen implements CodegenConfig {
if (schema == null) {
throw new RuntimeException("Request body cannot be null. Possible cause: missing schema in body parameter (OAS v2): " + body);
}
+ codegenParameter.setContent(getContent(body.getContent(), imports));
if (StringUtils.isNotBlank(schema.get$ref())) {
name = ModelUtils.getSimpleRef(schema.get$ref());
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java
index 86af0181b3d..75e466165a5 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java
@@ -505,7 +505,7 @@ public abstract class AbstractDartCodegen extends DefaultCodegen {
super.postProcessModelProperty(model, property);
if (!model.isEnum && property.isEnum) {
// These are inner enums, enums which do not exist as models, just as properties.
- // They are handled via the enum_inline template and and are generated in the
+ // They are handled via the enum_inline template and are generated in the
// same file as the containing class. To prevent name clashes the inline enum classes
// are prefix with the classname of the containing class in the template.
// Here the datatypeWithEnum template variable gets updated to match that scheme.
@@ -529,9 +529,9 @@ public abstract class AbstractDartCodegen extends DefaultCodegen {
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) {
final CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
for (CodegenResponse r : op.responses) {
- // By default only set types are automatically added to operation imports, not sure why.
+ // By default, only set types are automatically added to operation imports, not sure why.
// Add all container type imports here, by default 'dart:core' imports are skipped
- // but other sub classes may required specific container type imports.
+ // but other sub-classes may require specific container type imports.
if (r.containerType != null && typeMapping().containsKey(r.containerType)) {
final String value = typeMapping().get(r.containerType);
if (needToImport(value)) {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CLibcurlClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CLibcurlClientCodegen.java
index d48d0f77489..788639ab1d7 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CLibcurlClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CLibcurlClientCodegen.java
@@ -323,6 +323,7 @@ public class CLibcurlClientCodegen extends DefaultCodegen implements CodegenConf
// root folder
supportingFiles.add(new SupportingFile("CMakeLists.txt.mustache", "", "CMakeLists.txt"));
+ supportingFiles.add(new SupportingFile("Packing.cmake.mustache", "", "Packing.cmake"));
supportingFiles.add(new SupportingFile("libcurl.licence.mustache", "", "libcurl.licence"));
supportingFiles.add(new SupportingFile("uncrustify-rules.cfg.mustache", "", "uncrustify-rules.cfg"));
supportingFiles.add(new SupportingFile("README.md.mustache", "", "README.md"));
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNetCoreClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNetCoreClientCodegen.java
index b6e54b0fa21..1d6a13603f6 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNetCoreClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNetCoreClientCodegen.java
@@ -70,7 +70,8 @@ public class CSharpNetCoreClientCodegen extends AbstractCSharpCodegen {
FrameworkStrategy.NETCOREAPP_3_0,
FrameworkStrategy.NETCOREAPP_3_1,
FrameworkStrategy.NETFRAMEWORK_4_7,
- FrameworkStrategy.NET_5_0
+ FrameworkStrategy.NET_5_0,
+ FrameworkStrategy.NET_6_0
);
private static FrameworkStrategy defaultFramework = FrameworkStrategy.NETSTANDARD_2_0;
protected final Map frameworks;
@@ -1001,6 +1002,8 @@ public class CSharpNetCoreClientCodegen extends AbstractCSharpCodegen {
};
static FrameworkStrategy NET_5_0 = new FrameworkStrategy("net5.0", ".NET 5.0 compatible", "net5.0", Boolean.FALSE) {
};
+ static FrameworkStrategy NET_6_0 = new FrameworkStrategy("net6.0", ".NET 6.0 compatible", "net6.0", Boolean.FALSE) {
+ };
protected String name;
protected String description;
protected String testTargetFramework;
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNetCoreReducedClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNetCoreReducedClientCodegen.java
new file mode 100644
index 00000000000..d0447bd6968
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpNetCoreReducedClientCodegen.java
@@ -0,0 +1,1151 @@
+/*
+ * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openapitools.codegen.languages;
+
+import com.google.common.collect.ImmutableMap;
+import com.samskivert.mustache.Mustache;
+import io.swagger.v3.oas.models.media.ArraySchema;
+import io.swagger.v3.oas.models.media.ComposedSchema;
+import io.swagger.v3.oas.models.media.Schema;
+import org.openapitools.codegen.*;
+import org.openapitools.codegen.meta.features.*;
+import org.openapitools.codegen.utils.ModelUtils;
+import org.openapitools.codegen.utils.ProcessUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import static org.apache.commons.lang3.StringUtils.isEmpty;
+import static org.openapitools.codegen.utils.StringUtils.camelize;
+import static org.openapitools.codegen.utils.StringUtils.underscore;
+
+@SuppressWarnings("Duplicates")
+public class CSharpNetCoreReducedClientCodegen extends AbstractCSharpCodegen {
+ // Defines the sdk option for targeted frameworks, which differs from targetFramework and targetFrameworkNuget
+ protected static final String MCS_NET_VERSION_KEY = "x-mcs-sdk";
+ protected static final String SUPPORTS_UWP = "supportsUWP";
+ protected static final String SUPPORTS_RETRY = "supportsRetry";
+
+ protected static final String NET_STANDARD = "netStandard";
+
+ // HTTP libraries
+ protected static final String RESTSHARP = "restsharp";
+ protected static final String HTTPCLIENT = "httpclient";
+
+ // Project Variable, determined from target framework. Not intended to be user-settable.
+ protected static final String TARGET_FRAMEWORK_IDENTIFIER = "targetFrameworkIdentifier";
+ // Project Variable, determined from target framework. Not intended to be user-settable.
+ protected static final String TARGET_FRAMEWORK_VERSION = "targetFrameworkVersion";
+
+ @SuppressWarnings("hiding")
+ private final Logger LOGGER = LoggerFactory.getLogger(CSharpClientCodegen.class);
+ private static final List frameworkStrategies = Arrays.asList(
+ FrameworkStrategy.NETSTANDARD_1_3,
+ FrameworkStrategy.NETSTANDARD_1_4,
+ FrameworkStrategy.NETSTANDARD_1_5,
+ FrameworkStrategy.NETSTANDARD_1_6,
+ FrameworkStrategy.NETSTANDARD_2_0,
+ FrameworkStrategy.NETSTANDARD_2_1,
+ FrameworkStrategy.NETCOREAPP_2_0,
+ FrameworkStrategy.NETCOREAPP_2_1,
+ FrameworkStrategy.NETCOREAPP_3_0,
+ FrameworkStrategy.NETCOREAPP_3_1,
+ FrameworkStrategy.NETFRAMEWORK_4_7,
+ FrameworkStrategy.NET_5_0
+ );
+ private static FrameworkStrategy defaultFramework = FrameworkStrategy.NETSTANDARD_2_0;
+ protected final Map frameworks;
+ protected String packageGuid = "{" + java.util.UUID.randomUUID().toString().toUpperCase(Locale.ROOT) + "}";
+ protected String clientPackage = "Org.OpenAPITools.Client";
+ protected String apiDocPath = "docs/";
+ protected String modelDocPath = "docs/";
+
+ // Defines TargetFrameworkVersion in csproj files
+ protected String targetFramework = defaultFramework.name;
+ protected String testTargetFramework = defaultFramework.testTargetFramework;
+
+ // Defines nuget identifiers for target framework
+ protected String targetFrameworkNuget = targetFramework;
+
+ protected boolean supportsRetry = Boolean.TRUE;
+ protected boolean supportsAsync = Boolean.TRUE;
+ protected boolean netStandard = Boolean.FALSE;
+
+ protected boolean validatable = Boolean.TRUE;
+ protected Map regexModifiers;
+ // By default, generated code is considered public
+ protected boolean nonPublicApi = Boolean.FALSE;
+
+ protected boolean caseInsensitiveResponseHeaders = Boolean.FALSE;
+ protected String releaseNote = "Minor update";
+ protected String licenseId;
+ protected String packageTags;
+ protected boolean useOneOfDiscriminatorLookup = false; // use oneOf discriminator's mapping for model lookup
+
+ protected boolean needsCustomHttpMethod = false;
+ protected boolean needsUriBuilder = false;
+
+ public CSharpNetCoreReducedClientCodegen() {
+ super();
+
+ modifyFeatureSet(features -> features
+ .includeDocumentationFeatures(DocumentationFeature.Readme)
+ .securityFeatures(EnumSet.of(
+ SecurityFeature.OAuth2_Implicit,
+ SecurityFeature.BasicAuth,
+ SecurityFeature.ApiKey
+ ))
+ .excludeGlobalFeatures(
+ GlobalFeature.XMLStructureDefinitions,
+ GlobalFeature.Callbacks,
+ GlobalFeature.LinkObjects,
+ GlobalFeature.ParameterStyling
+ )
+ .includeSchemaSupportFeatures(
+ SchemaSupportFeature.Polymorphism
+ )
+ .includeParameterFeatures(
+ ParameterFeature.Cookie
+ )
+ .includeClientModificationFeatures(
+ ClientModificationFeature.BasePath,
+ ClientModificationFeature.UserAgent
+ )
+ );
+
+ // mapped non-nullable type without ?
+ typeMapping = new HashMap();
+ typeMapping.put("string", "string");
+ typeMapping.put("binary", "byte[]");
+ typeMapping.put("ByteArray", "byte[]");
+ typeMapping.put("boolean", "bool");
+ typeMapping.put("integer", "int");
+ typeMapping.put("float", "float");
+ typeMapping.put("long", "long");
+ typeMapping.put("double", "double");
+ typeMapping.put("number", "decimal");
+ typeMapping.put("decimal", "decimal");
+ typeMapping.put("DateTime", "DateTime");
+ typeMapping.put("date", "DateTime");
+ typeMapping.put("file", "System.IO.Stream");
+ typeMapping.put("array", "List");
+ typeMapping.put("list", "List");
+ typeMapping.put("map", "Dictionary");
+ typeMapping.put("object", "Object");
+ typeMapping.put("UUID", "Guid");
+ typeMapping.put("URI", "string");
+ typeMapping.put("AnyType", "Object");
+
+ setSupportNullable(Boolean.TRUE);
+ hideGenerationTimestamp = Boolean.TRUE;
+ supportsInheritance = true;
+ modelTemplateFiles.put("model.mustache", ".cs");
+ apiTemplateFiles.put("api.mustache", ".cs");
+ modelDocTemplateFiles.put("model_doc.mustache", ".md");
+ apiDocTemplateFiles.put("api_doc.mustache", ".md");
+ embeddedTemplateDir = templateDir = "csharp-netcore";
+
+ cliOptions.clear();
+
+ // CLI options
+ addOption(CodegenConstants.PACKAGE_NAME,
+ "C# package name (convention: Title.Case).",
+ this.packageName);
+
+ addOption(CodegenConstants.PACKAGE_VERSION,
+ "C# package version.",
+ this.packageVersion);
+
+ addOption(CodegenConstants.SOURCE_FOLDER,
+ CodegenConstants.SOURCE_FOLDER_DESC,
+ sourceFolder);
+
+ addOption(CodegenConstants.OPTIONAL_PROJECT_GUID,
+ CodegenConstants.OPTIONAL_PROJECT_GUID_DESC,
+ null);
+
+ addOption(CodegenConstants.INTERFACE_PREFIX,
+ CodegenConstants.INTERFACE_PREFIX_DESC,
+ interfacePrefix);
+
+ addOption(CodegenConstants.LICENSE_ID,
+ CodegenConstants.LICENSE_ID_DESC,
+ this.licenseId);
+
+ addOption(CodegenConstants.RELEASE_NOTE,
+ CodegenConstants.RELEASE_NOTE_DESC,
+ this.releaseNote);
+
+ addOption(CodegenConstants.PACKAGE_TAGS,
+ CodegenConstants.PACKAGE_TAGS_DESC,
+ this.packageTags);
+
+ CliOption framework = new CliOption(
+ CodegenConstants.DOTNET_FRAMEWORK,
+ CodegenConstants.DOTNET_FRAMEWORK_DESC
+ );
+
+ CliOption disallowAdditionalPropertiesIfNotPresentOpt = CliOption.newBoolean(
+ CodegenConstants.DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT,
+ CodegenConstants.DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT_DESC).defaultValue(Boolean.TRUE.toString());
+ Map disallowAdditionalPropertiesIfNotPresentOpts = new HashMap<>();
+ disallowAdditionalPropertiesIfNotPresentOpts.put("false",
+ "The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.");
+ disallowAdditionalPropertiesIfNotPresentOpts.put("true",
+ "Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.");
+ disallowAdditionalPropertiesIfNotPresentOpt.setEnum(disallowAdditionalPropertiesIfNotPresentOpts);
+ cliOptions.add(disallowAdditionalPropertiesIfNotPresentOpt);
+ this.setDisallowAdditionalPropertiesIfNotPresent(true);
+
+ ImmutableMap.Builder frameworkBuilder = new ImmutableMap.Builder<>();
+ for (FrameworkStrategy frameworkStrategy : frameworkStrategies) {
+ frameworkBuilder.put(frameworkStrategy.name, frameworkStrategy.description);
+ }
+
+ frameworks = frameworkBuilder.build();
+
+ framework.defaultValue(this.targetFramework);
+ framework.setEnum(frameworks);
+ cliOptions.add(framework);
+
+ CliOption modelPropertyNaming = new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC);
+ cliOptions.add(modelPropertyNaming.defaultValue("PascalCase"));
+
+ // CLI Switches
+ addSwitch(CodegenConstants.NULLABLE_REFERENCE_TYPES,
+ CodegenConstants.NULLABLE_REFERENCE_TYPES_DESC,
+ this.nullReferenceTypesFlag);
+
+ addSwitch(CodegenConstants.HIDE_GENERATION_TIMESTAMP,
+ CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC,
+ this.hideGenerationTimestamp);
+
+ addSwitch(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG,
+ CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC,
+ this.sortParamsByRequiredFlag);
+
+ addSwitch(CodegenConstants.USE_DATETIME_OFFSET,
+ CodegenConstants.USE_DATETIME_OFFSET_DESC,
+ this.useDateTimeOffsetFlag);
+
+ addSwitch(CodegenConstants.USE_COLLECTION,
+ CodegenConstants.USE_COLLECTION_DESC,
+ this.useCollection);
+
+ addSwitch(CodegenConstants.RETURN_ICOLLECTION,
+ CodegenConstants.RETURN_ICOLLECTION_DESC,
+ this.returnICollection);
+
+ addSwitch(CodegenConstants.OPTIONAL_METHOD_ARGUMENT,
+ "C# Optional method argument, e.g. void square(int x=10) (.net 4.0+ only).",
+ this.optionalMethodArgumentFlag);
+
+ addSwitch(CodegenConstants.OPTIONAL_ASSEMBLY_INFO,
+ CodegenConstants.OPTIONAL_ASSEMBLY_INFO_DESC,
+ this.optionalAssemblyInfoFlag);
+
+ addSwitch(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES,
+ CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES_DESC,
+ this.optionalEmitDefaultValuesFlag);
+
+ addSwitch(CodegenConstants.OPTIONAL_CONDITIONAL_SERIALIZATION,
+ CodegenConstants.OPTIONAL_CONDITIONAL_SERIALIZATION_DESC,
+ this.conditionalSerialization);
+
+ addSwitch(CodegenConstants.OPTIONAL_PROJECT_FILE,
+ CodegenConstants.OPTIONAL_PROJECT_FILE_DESC,
+ this.optionalProjectFileFlag);
+
+ // NOTE: This will reduce visibility of all public members in templates. Users can use InternalsVisibleTo
+ // https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute(v=vs.110).aspx
+ // to expose to shared code if the generated code is not embedded into another project. Otherwise, users of codegen
+ // should rely on default public visibility.
+ addSwitch(CodegenConstants.NON_PUBLIC_API,
+ CodegenConstants.NON_PUBLIC_API_DESC,
+ this.nonPublicApi);
+
+ addSwitch(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS,
+ CodegenConstants.ALLOW_UNICODE_IDENTIFIERS_DESC,
+ this.allowUnicodeIdentifiers);
+
+ addSwitch(CodegenConstants.NETCORE_PROJECT_FILE,
+ CodegenConstants.NETCORE_PROJECT_FILE_DESC,
+ this.netCoreProjectFileFlag);
+
+ addSwitch(CodegenConstants.VALIDATABLE,
+ CodegenConstants.VALIDATABLE_DESC,
+ this.validatable);
+
+ addSwitch(CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP,
+ CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP_DESC,
+ this.caseInsensitiveResponseHeaders);
+
+ addSwitch(CodegenConstants.CASE_INSENSITIVE_RESPONSE_HEADERS,
+ CodegenConstants.CASE_INSENSITIVE_RESPONSE_HEADERS_DESC,
+ this.caseInsensitiveResponseHeaders);
+
+ regexModifiers = new HashMap<>();
+ regexModifiers.put('i', "IgnoreCase");
+ regexModifiers.put('m', "Multiline");
+ regexModifiers.put('s', "Singleline");
+ regexModifiers.put('x', "IgnorePatternWhitespace");
+
+ supportedLibraries.put(HTTPCLIENT, "HttpClient (https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient) "
+ + "(Experimental. May subject to breaking changes without further notice.)");
+ supportedLibraries.put(RESTSHARP, "RestSharp (https://github.com/restsharp/RestSharp)");
+
+ CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "HTTP library template (sub-template) to use");
+ libraryOption.setEnum(supportedLibraries);
+ // set RESTSHARP as the default
+ libraryOption.setDefault(RESTSHARP);
+ cliOptions.add(libraryOption);
+ setLibrary(RESTSHARP);
+ }
+
+ @Override
+ public String apiDocFileFolder() {
+ return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
+ }
+
+ @Override
+ public String apiTestFileFolder() {
+ return outputFolder + File.separator + testFolder + File.separator + testPackageName() + File.separator + apiPackage();
+ }
+
+ @Override
+ public CodegenModel fromModel(String name, Schema model) {
+ Map allDefinitions = ModelUtils.getSchemas(this.openAPI);
+ CodegenModel codegenModel = super.fromModel(name, model);
+ if (allDefinitions != null && codegenModel != null && codegenModel.parent != null) {
+ final Schema parentModel = allDefinitions.get(toModelName(codegenModel.parent));
+ if (parentModel != null) {
+ final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
+ if (codegenModel.hasEnums) {
+ codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel);
+ }
+
+ Map propertyHash = new HashMap<>(codegenModel.vars.size());
+ for (final CodegenProperty property : codegenModel.vars) {
+ propertyHash.put(property.name, property);
+ }
+
+ for (final CodegenProperty property : codegenModel.readWriteVars) {
+ if (property.defaultValue == null && parentCodegenModel.discriminator != null && property.name.equals(parentCodegenModel.discriminator.getPropertyName())) {
+ property.defaultValue = "\"" + name + "\"";
+ }
+ }
+
+ CodegenProperty last = null;
+ for (final CodegenProperty property : parentCodegenModel.vars) {
+ // helper list of parentVars simplifies templating
+ if (!propertyHash.containsKey(property.name)) {
+ final CodegenProperty parentVar = property.clone();
+ parentVar.isInherited = true;
+ last = parentVar;
+ LOGGER.debug("adding parent variable {}", property.name);
+ codegenModel.parentVars.add(parentVar);
+ }
+ }
+ }
+ }
+
+ // Cleanup possible duplicates. Currently, readWriteVars can contain the same property twice. May or may not be isolated to C#.
+ if (codegenModel != null && codegenModel.readWriteVars != null && codegenModel.readWriteVars.size() > 1) {
+ int length = codegenModel.readWriteVars.size() - 1;
+ for (int i = length; i > (length / 2); i--) {
+ final CodegenProperty codegenProperty = codegenModel.readWriteVars.get(i);
+ // If the property at current index is found earlier in the list, remove this last instance.
+ if (codegenModel.readWriteVars.indexOf(codegenProperty) < i) {
+ codegenModel.readWriteVars.remove(i);
+ }
+ }
+ }
+
+ return codegenModel;
+ }
+
+ @Override
+ public String getHelp() {
+ return "Generates a C# client library (.NET Standard, .NET Core).";
+ }
+
+ public String getModelPropertyNaming() {
+ return this.modelPropertyNaming;
+ }
+
+ public void setModelPropertyNaming(String naming) {
+ if ("original".equals(naming) || "camelCase".equals(naming) ||
+ "PascalCase".equals(naming) || "snake_case".equals(naming)) {
+ this.modelPropertyNaming = naming;
+ } else {
+ throw new IllegalArgumentException("Invalid model property naming '" +
+ naming + "'. Must be 'original', 'camelCase', " +
+ "'PascalCase' or 'snake_case'");
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "csharp-netcore";
+ }
+
+ public String getNameUsingModelPropertyNaming(String name) {
+ switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) {
+ case original:
+ return name;
+ case camelCase:
+ return camelize(name, true);
+ case PascalCase:
+ return camelize(name);
+ case snake_case:
+ return underscore(name);
+ default:
+ throw new IllegalArgumentException("Invalid model property naming '" +
+ name + "'. Must be 'original', 'camelCase', " +
+ "'PascalCase' or 'snake_case'");
+ }
+ }
+
+ @Override
+ public String getNullableType(Schema p, String type) {
+ if (languageSpecificPrimitives.contains(type)) {
+ if (isSupportNullable() && ModelUtils.isNullable(p) && nullableType.contains(type)) {
+ return type + "?";
+ } else {
+ return type;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public CodegenType getTag() {
+ return CodegenType.CLIENT;
+ }
+
+ public boolean isNonPublicApi() {
+ return nonPublicApi;
+ }
+
+ public void setNonPublicApi(final boolean nonPublicApi) {
+ this.nonPublicApi = nonPublicApi;
+ }
+
+ @Override
+ public String modelDocFileFolder() {
+ return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
+ }
+
+ @Override
+ public String modelTestFileFolder() {
+ return outputFolder + File.separator + testFolder + File.separator + testPackageName() + File.separator + modelPackage();
+ }
+
+ @Override
+ public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
+ postProcessPattern(property.pattern, property.vendorExtensions);
+ postProcessEmitDefaultValue(property.vendorExtensions);
+
+ super.postProcessModelProperty(model, property);
+ }
+
+ @Override
+ public void postProcessParameter(CodegenParameter parameter) {
+ postProcessPattern(parameter.pattern, parameter.vendorExtensions);
+ postProcessEmitDefaultValue(parameter.vendorExtensions);
+ super.postProcessParameter(parameter);
+ }
+
+ /*
+ * The pattern spec follows the Perl convention and style of modifiers. .NET
+ * does not support this syntax directly so we need to convert the pattern to a .NET compatible
+ * format and apply modifiers in a compatible way.
+ * See https://msdn.microsoft.com/en-us/library/yd1hzczs(v=vs.110).aspx for .NET options.
+ */
+ public void postProcessPattern(String pattern, Map vendorExtensions) {
+ if (pattern != null) {
+ int i = pattern.lastIndexOf('/');
+
+ //Must follow Perl /pattern/modifiers convention
+ if (pattern.charAt(0) != '/' || i < 2) {
+ throw new IllegalArgumentException("Pattern must follow the Perl "
+ + "/pattern/modifiers convention. " + pattern + " is not valid.");
+ }
+
+ String regex = pattern.substring(1, i).replace("'", "\'").replace("\"", "\"\"");
+ List modifiers = new ArrayList();
+
+ // perl requires an explicit modifier to be culture specific and .NET is the reverse.
+ modifiers.add("CultureInvariant");
+
+ for (char c : pattern.substring(i).toCharArray()) {
+ if (regexModifiers.containsKey(c)) {
+ String modifier = regexModifiers.get(c);
+ modifiers.add(modifier);
+ } else if (c == 'l') {
+ modifiers.remove("CultureInvariant");
+ }
+ }
+
+ vendorExtensions.put("x-regex", regex);
+ vendorExtensions.put("x-modifiers", modifiers);
+ }
+ }
+
+ public void postProcessEmitDefaultValue(Map vendorExtensions) {
+ vendorExtensions.put("x-emit-default-value", optionalEmitDefaultValuesFlag);
+ }
+
+ @Override
+ public Mustache.Compiler processCompiler(Mustache.Compiler compiler) {
+ // To avoid unexpected behaviors when options are passed programmatically such as { "supportsAsync": "" }
+ return super.processCompiler(compiler).emptyStringIsFalse(true);
+ }
+
+ @Override
+ public void processOpts() {
+ this.setLegacyDiscriminatorBehavior(false);
+
+ super.processOpts();
+
+ /*
+ * NOTE: When supporting boolean additionalProperties, you should read the value and write it back as a boolean.
+ * This avoids oddities where additionalProperties contains "false" rather than false, which will cause the
+ * templating engine to behave unexpectedly.
+ *
+ * Use the pattern:
+ * if (additionalProperties.containsKey(prop)) convertPropertyToBooleanAndWriteBack(prop);
+ */
+
+ if (additionalProperties.containsKey(CodegenConstants.DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT)) {
+ this.setDisallowAdditionalPropertiesIfNotPresent(Boolean.parseBoolean(additionalProperties
+ .get(CodegenConstants.DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT).toString()));
+ }
+
+ if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES)) {
+ setOptionalEmitDefaultValuesFlag(convertPropertyToBooleanAndWriteBack(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES));
+ } else {
+ additionalProperties.put(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES, optionalEmitDefaultValuesFlag);
+ }
+
+ if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_CONDITIONAL_SERIALIZATION)) {
+ setConditionalSerialization(convertPropertyToBooleanAndWriteBack(CodegenConstants.OPTIONAL_CONDITIONAL_SERIALIZATION));
+ } else {
+ additionalProperties.put(CodegenConstants.OPTIONAL_CONDITIONAL_SERIALIZATION, conditionalSerialization);
+ }
+
+ if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) {
+ setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING));
+ }
+
+ if (isEmpty(apiPackage)) {
+ setApiPackage("Api");
+ }
+ if (isEmpty(modelPackage)) {
+ setModelPackage("Model");
+ }
+
+ clientPackage = "Client";
+
+ if (RESTSHARP.equals(getLibrary())) {
+ additionalProperties.put("useRestSharp", true);
+ needsCustomHttpMethod = true;
+ } else if (HTTPCLIENT.equals(getLibrary())) {
+ setLibrary(HTTPCLIENT);
+ additionalProperties.put("useHttpClient", true);
+ needsUriBuilder = true;
+ } else {
+ throw new RuntimeException("Invalid HTTP library " + getLibrary() + ". Only restsharp, httpclient are supported.");
+ }
+
+ String inputFramework = (String) additionalProperties.getOrDefault(CodegenConstants.DOTNET_FRAMEWORK, defaultFramework.name);
+ String[] frameworks;
+ List strategies = new ArrayList<>();
+
+ if (inputFramework.contains(";")) {
+ // multiple target framework
+ frameworks = inputFramework.split(";");
+ additionalProperties.put("multiTarget", true);
+ } else {
+ // just a single value
+ frameworks = new String[]{inputFramework};
+ }
+
+ for (String framework : frameworks) {
+ boolean strategyMatched = false;
+ for (FrameworkStrategy frameworkStrategy : frameworkStrategies) {
+ if (framework.equals(frameworkStrategy.name)) {
+ strategies.add(frameworkStrategy);
+ strategyMatched = true;
+ }
+
+ if (frameworkStrategy != FrameworkStrategy.NETSTANDARD_2_0 && "restsharp".equals(getLibrary())) {
+ LOGGER.warn("If using built-in templates, RestSharp only supports netstandard 2.0 or later.");
+ }
+ }
+
+ if (!strategyMatched) {
+ // throws exception if the input targetFramework is invalid
+ throw new IllegalArgumentException("The input (" + inputFramework + ") contains Invalid .NET framework version: " +
+ framework + ". List of supported versions: " +
+ frameworkStrategies.stream()
+ .map(p -> p.name)
+ .collect(Collectors.joining(", ")));
+ }
+ }
+
+ configureAdditionalPropertiesForFrameworks(additionalProperties, strategies);
+ setTargetFrameworkNuget(strategies);
+ setTargetFramework(strategies);
+ setTestTargetFramework(strategies);
+
+ setSupportsAsync(Boolean.TRUE);
+ setNetStandard(strategies.stream().anyMatch(p -> Boolean.TRUE.equals(p.isNetStandard)));
+
+ if (!netStandard) {
+ setNetCoreProjectFileFlag(true);
+ }
+
+ if (additionalProperties.containsKey(CodegenConstants.GENERATE_PROPERTY_CHANGED)) {
+ LOGGER.warn("{} is not supported in the .NET Standard generator.", CodegenConstants.GENERATE_PROPERTY_CHANGED);
+ additionalProperties.remove(CodegenConstants.GENERATE_PROPERTY_CHANGED);
+ }
+
+ final AtomicReference excludeTests = new AtomicReference<>();
+ syncBooleanProperty(additionalProperties, CodegenConstants.EXCLUDE_TESTS, excludeTests::set, false);
+
+ syncStringProperty(additionalProperties, "clientPackage", (s) -> {}, clientPackage);
+
+ syncStringProperty(additionalProperties, CodegenConstants.API_PACKAGE, this::setApiPackage, apiPackage);
+ syncStringProperty(additionalProperties, CodegenConstants.MODEL_PACKAGE, this::setModelPackage, modelPackage);
+ syncStringProperty(additionalProperties, CodegenConstants.OPTIONAL_PROJECT_GUID, this::setPackageGuid, packageGuid);
+ syncStringProperty(additionalProperties, "targetFrameworkNuget", this::setTargetFrameworkNuget, this.targetFrameworkNuget);
+ syncStringProperty(additionalProperties, "testTargetFramework", this::setTestTargetFramework, this.testTargetFramework);
+
+ syncBooleanProperty(additionalProperties, "netStandard", this::setNetStandard, this.netStandard);
+
+ syncBooleanProperty(additionalProperties, CodegenConstants.VALIDATABLE, this::setValidatable, this.validatable);
+ syncBooleanProperty(additionalProperties, CodegenConstants.SUPPORTS_ASYNC, this::setSupportsAsync, this.supportsAsync);
+ syncBooleanProperty(additionalProperties, SUPPORTS_RETRY, this::setSupportsRetry, this.supportsRetry);
+ syncBooleanProperty(additionalProperties, CodegenConstants.OPTIONAL_METHOD_ARGUMENT, this::setOptionalMethodArgumentFlag, optionalMethodArgumentFlag);
+ syncBooleanProperty(additionalProperties, CodegenConstants.NON_PUBLIC_API, this::setNonPublicApi, isNonPublicApi());
+ syncBooleanProperty(additionalProperties, CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, this::setUseOneOfDiscriminatorLookup, this.useOneOfDiscriminatorLookup);
+
+ final String testPackageName = testPackageName();
+ String packageFolder = sourceFolder + File.separator + packageName;
+ String clientPackageDir = packageFolder + File.separator + clientPackage;
+ String modelPackageDir = packageFolder + File.separator + modelPackage;
+ String testPackageFolder = testFolder + File.separator + testPackageName;
+
+ additionalProperties.put("testPackageName", testPackageName);
+
+ //Compute the relative path to the bin directory where the external assemblies live
+ //This is necessary to properly generate the project file
+ int packageDepth = packageFolder.length() - packageFolder.replace(java.io.File.separator, "").length();
+ String binRelativePath = "..\\";
+ for (int i = 0; i < packageDepth; i = i + 1) {
+ binRelativePath += "..\\";
+ }
+ binRelativePath += "vendor";
+ additionalProperties.put("binRelativePath", binRelativePath);
+
+ if (HTTPCLIENT.equals(getLibrary())) {
+ supportingFiles.add(new SupportingFile("FileParameter.mustache", clientPackageDir, "FileParameter.cs"));
+ typeMapping.put("file", "FileParameter");
+ }
+
+ supportingFiles.add(new SupportingFile("IApiAccessor.mustache", clientPackageDir, "IApiAccessor.cs"));
+ supportingFiles.add(new SupportingFile("Configuration.mustache", clientPackageDir, "Configuration.cs"));
+ supportingFiles.add(new SupportingFile("ApiClient.mustache", clientPackageDir, "ApiClient.cs"));
+ supportingFiles.add(new SupportingFile("ApiException.mustache", clientPackageDir, "ApiException.cs"));
+ supportingFiles.add(new SupportingFile("ApiResponse.mustache", clientPackageDir, "ApiResponse.cs"));
+ supportingFiles.add(new SupportingFile("ExceptionFactory.mustache", clientPackageDir, "ExceptionFactory.cs"));
+ supportingFiles.add(new SupportingFile("OpenAPIDateConverter.mustache", clientPackageDir, "OpenAPIDateConverter.cs"));
+ supportingFiles.add(new SupportingFile("ClientUtils.mustache", clientPackageDir, "ClientUtils.cs"));
+ if (needsCustomHttpMethod) {
+ supportingFiles.add(new SupportingFile("HttpMethod.mustache", clientPackageDir, "HttpMethod.cs"));
+ }
+ if (needsUriBuilder) {
+ supportingFiles.add(new SupportingFile("WebRequestPathBuilder.mustache", clientPackageDir, "WebRequestPathBuilder.cs"));
+ }
+ if (ProcessUtils.hasHttpSignatureMethods(openAPI)) {
+ supportingFiles.add(new SupportingFile("HttpSigningConfiguration.mustache", clientPackageDir, "HttpSigningConfiguration.cs"));
+ }
+ if (supportsAsync) {
+ supportingFiles.add(new SupportingFile("IAsynchronousClient.mustache", clientPackageDir, "IAsynchronousClient.cs"));
+ }
+ supportingFiles.add(new SupportingFile("ISynchronousClient.mustache", clientPackageDir, "ISynchronousClient.cs"));
+ supportingFiles.add(new SupportingFile("RequestOptions.mustache", clientPackageDir, "RequestOptions.cs"));
+ supportingFiles.add(new SupportingFile("Multimap.mustache", clientPackageDir, "Multimap.cs"));
+
+ if (supportsRetry) {
+ supportingFiles.add(new SupportingFile("RetryConfiguration.mustache", clientPackageDir, "RetryConfiguration.cs"));
+ }
+
+ supportingFiles.add(new SupportingFile("IReadableConfiguration.mustache",
+ clientPackageDir, "IReadableConfiguration.cs"));
+ supportingFiles.add(new SupportingFile("GlobalConfiguration.mustache",
+ clientPackageDir, "GlobalConfiguration.cs"));
+
+ // Only write out test related files if excludeTests is unset or explicitly set to false (see start of this method)
+ if (Boolean.FALSE.equals(excludeTests.get())) {
+ modelTestTemplateFiles.put("model_test.mustache", ".cs");
+ apiTestTemplateFiles.put("api_test.mustache", ".cs");
+ }
+
+ supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
+ supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
+ supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
+
+ supportingFiles.add(new SupportingFile("appveyor.mustache", "", "appveyor.yml"));
+ supportingFiles.add(new SupportingFile("AbstractOpenAPISchema.mustache", modelPackageDir, "AbstractOpenAPISchema.cs"));
+
+ additionalProperties.put("apiDocPath", apiDocPath);
+ additionalProperties.put("modelDocPath", modelDocPath);
+ }
+
+ public void setNetStandard(Boolean netStandard) {
+ this.netStandard = netStandard;
+ }
+
+ public void setOptionalAssemblyInfoFlag(boolean flag) {
+ this.optionalAssemblyInfoFlag = flag;
+ }
+
+ public void setOptionalEmitDefaultValuesFlag(boolean flag) {
+ this.optionalEmitDefaultValuesFlag = flag;
+ }
+
+ public void setConditionalSerialization(boolean flag) {
+ this.conditionalSerialization = flag;
+ }
+
+ public void setOptionalProjectFileFlag(boolean flag) {
+ this.optionalProjectFileFlag = flag;
+ }
+
+ public void setPackageGuid(String packageGuid) {
+ this.packageGuid = packageGuid;
+ }
+
+ @Override
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ @Override
+ public void setPackageVersion(String packageVersion) {
+ this.packageVersion = packageVersion;
+ }
+
+ public void setSupportsAsync(Boolean supportsAsync) {
+ this.supportsAsync = supportsAsync;
+ }
+
+ public void setSupportsRetry(Boolean supportsRetry) {
+ this.supportsRetry = supportsRetry;
+ }
+
+ public void setTargetFramework(String dotnetFramework) {
+ if (!frameworks.containsKey(dotnetFramework)) {
+ throw new IllegalArgumentException("Invalid .NET framework version: " +
+ dotnetFramework + ". List of supported versions: " +
+ frameworkStrategies.stream()
+ .map(p -> p.name)
+ .collect(Collectors.joining(", ")));
+ } else {
+ this.targetFramework = dotnetFramework;
+ }
+ LOGGER.info("Generating code for .NET Framework {}", this.targetFramework);
+ }
+
+ public void setTargetFramework(List strategies) {
+ for (FrameworkStrategy strategy : strategies) {
+ if (!frameworks.containsKey(strategy.name)) {
+ throw new IllegalArgumentException("Invalid .NET framework version: " +
+ strategy.name + ". List of supported versions: " +
+ frameworkStrategies.stream()
+ .map(p -> p.name)
+ .collect(Collectors.joining(", ")));
+ }
+ }
+ this.targetFramework = strategies.stream().map(p -> p.name)
+ .collect(Collectors.joining(";"));
+ LOGGER.info("Generating code for .NET Framework {}", this.targetFramework);
+ }
+
+ public void setTestTargetFramework(String testTargetFramework) {
+ this.testTargetFramework = testTargetFramework;
+ }
+
+ public void setTestTargetFramework(List strategies) {
+ this.testTargetFramework = strategies.stream().map(p -> p.testTargetFramework)
+ .collect(Collectors.joining(";"));
+ }
+
+ public void setTargetFrameworkNuget(String targetFrameworkNuget) {
+ this.targetFrameworkNuget = targetFrameworkNuget;
+ }
+
+ public void setTargetFrameworkNuget(List strategies) {
+ this.targetFrameworkNuget = strategies.stream().map(p -> p.getNugetFrameworkIdentifier())
+ .collect(Collectors.joining(";"));
+ }
+
+ public void setValidatable(boolean validatable) {
+ this.validatable = validatable;
+ }
+
+ public void setCaseInsensitiveResponseHeaders(final Boolean caseInsensitiveResponseHeaders) {
+ this.caseInsensitiveResponseHeaders = caseInsensitiveResponseHeaders;
+ }
+
+ public void setLicenseId(String licenseId) {
+ this.licenseId = licenseId;
+ }
+
+ @Override
+ public void setReleaseNote(String releaseNote) {
+ this.releaseNote = releaseNote;
+ }
+
+ public void setPackageTags(String packageTags) {
+ this.packageTags = packageTags;
+ }
+
+ public void setUseOneOfDiscriminatorLookup(boolean useOneOfDiscriminatorLookup) {
+ this.useOneOfDiscriminatorLookup = useOneOfDiscriminatorLookup;
+ }
+
+ public boolean getUseOneOfDiscriminatorLookup() {
+ return this.useOneOfDiscriminatorLookup;
+ }
+
+ @Override
+ public String toEnumVarName(String value, String datatype) {
+ if (value.length() == 0) {
+ return "Empty";
+ }
+
+ // for symbol, e.g. $, #
+ if (getSymbolName(value) != null) {
+ return camelize(getSymbolName(value));
+ }
+
+ // number
+ if (datatype.startsWith("int") || datatype.startsWith("long") ||
+ datatype.startsWith("double") || datatype.startsWith("float")) {
+ String varName = "NUMBER_" + value;
+ varName = varName.replaceAll("-", "MINUS_");
+ varName = varName.replaceAll("\\+", "PLUS_");
+ varName = varName.replaceAll("\\.", "_DOT_");
+ return varName;
+ }
+
+ // string
+ String var = value.replaceAll(" ", "_");
+ var = camelize(var);
+ var = var.replaceAll("\\W+", "");
+
+ if (var.matches("\\d.*")) {
+ return "_" + var;
+ } else {
+ return var;
+ }
+ }
+
+ @Override
+ public String toModelDocFilename(String name) {
+ return toModelFilename(name);
+ }
+
+ @Override
+ public String toVarName(String name) {
+ // sanitize name
+ name = sanitizeName(name);
+
+ // if it's all upper case, do nothing
+ if (name.matches("^[A-Z_]*$")) {
+ return name;
+ }
+
+ name = getNameUsingModelPropertyNaming(name);
+
+ // for reserved word or word starting with number, append _
+ if (isReservedWord(name) || name.matches("^\\d.*")) {
+ name = escapeReservedWord(name);
+ }
+
+ // for function names in the model, escape with the "Property" prefix
+ if (propertySpecialKeywords.contains(name)) {
+ return camelize("property_" + name);
+ }
+
+ return name;
+ }
+
+ private CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenModel parentCodegenModel) {
+ // This generator uses inline classes to define enums, which breaks when
+ // dealing with models that have subTypes. To clean this up, we will analyze
+ // the parent and child models, look for enums that match, and remove
+ // them from the child models and leave them in the parent.
+ // Because the child models extend the parents, the enums will be available via the parent.
+
+ // Only bother with reconciliation if the parent model has enums.
+ if (parentCodegenModel.hasEnums) {
+
+ // Get the properties for the parent and child models
+ final List parentModelCodegenProperties = parentCodegenModel.vars;
+ List codegenProperties = codegenModel.vars;
+
+ // Iterate over all of the parent model properties
+ boolean removedChildEnum = false;
+ for (CodegenProperty parentModelCodegenProperty : parentModelCodegenProperties) {
+ // Look for enums
+ if (parentModelCodegenProperty.isEnum) {
+ // Now that we have found an enum in the parent class,
+ // and search the child class for the same enum.
+ Iterator iterator = codegenProperties.iterator();
+ while (iterator.hasNext()) {
+ CodegenProperty codegenProperty = iterator.next();
+ if (codegenProperty.isEnum && codegenProperty.equals(parentModelCodegenProperty)) {
+ // We found an enum in the child class that is
+ // a duplicate of the one in the parent, so remove it.
+ iterator.remove();
+ removedChildEnum = true;
+ }
+ }
+ }
+ }
+
+ if (removedChildEnum) {
+ codegenModel.vars = codegenProperties;
+ }
+ }
+
+ return codegenModel;
+ }
+
+ private void syncBooleanProperty(final Map additionalProperties, final String key, final Consumer setter, final Boolean defaultValue) {
+ if (additionalProperties.containsKey(key)) {
+ setter.accept(convertPropertyToBooleanAndWriteBack(key));
+ } else {
+ additionalProperties.put(key, defaultValue);
+ setter.accept(defaultValue);
+ }
+ }
+
+ private void syncStringProperty(final Map additionalProperties, final String key, final Consumer setter, final String defaultValue) {
+ if (additionalProperties.containsKey(key)) {
+ setter.accept((String) additionalProperties.get(key));
+ } else {
+ additionalProperties.put(key, defaultValue);
+ setter.accept(defaultValue);
+ }
+ }
+
+ // https://docs.microsoft.com/en-us/dotnet/standard/net-standard
+ @SuppressWarnings("Duplicates")
+ private static abstract class FrameworkStrategy {
+
+ private final Logger LOGGER = LoggerFactory.getLogger(CSharpClientCodegen.class);
+
+ static FrameworkStrategy NETSTANDARD_1_3 = new FrameworkStrategy("netstandard1.3", ".NET Standard 1.3 compatible", "netcoreapp2.0") {
+ };
+ static FrameworkStrategy NETSTANDARD_1_4 = new FrameworkStrategy("netstandard1.4", ".NET Standard 1.4 compatible", "netcoreapp2.0") {
+ };
+ static FrameworkStrategy NETSTANDARD_1_5 = new FrameworkStrategy("netstandard1.5", ".NET Standard 1.5 compatible", "netcoreapp2.0") {
+ };
+ static FrameworkStrategy NETSTANDARD_1_6 = new FrameworkStrategy("netstandard1.6", ".NET Standard 1.6 compatible", "netcoreapp2.0") {
+ };
+ static FrameworkStrategy NETSTANDARD_2_0 = new FrameworkStrategy("netstandard2.0", ".NET Standard 2.0 compatible", "netcoreapp2.0") {
+ };
+ static FrameworkStrategy NETSTANDARD_2_1 = new FrameworkStrategy("netstandard2.1", ".NET Standard 2.1 compatible", "netcoreapp3.0") {
+ };
+ static FrameworkStrategy NETCOREAPP_2_0 = new FrameworkStrategy("netcoreapp2.0", ".NET Core 2.0 compatible", "netcoreapp2.0", Boolean.FALSE) {
+ };
+ static FrameworkStrategy NETCOREAPP_2_1 = new FrameworkStrategy("netcoreapp2.1", ".NET Core 2.1 compatible", "netcoreapp2.1", Boolean.FALSE) {
+ };
+ static FrameworkStrategy NETCOREAPP_3_0 = new FrameworkStrategy("netcoreapp3.0", ".NET Core 3.0 compatible", "netcoreapp3.0", Boolean.FALSE) {
+ };
+ static FrameworkStrategy NETCOREAPP_3_1 = new FrameworkStrategy("netcoreapp3.1", ".NET Core 3.1 compatible", "netcoreapp3.1", Boolean.FALSE) {
+ };
+ static FrameworkStrategy NETFRAMEWORK_4_7 = new FrameworkStrategy("net47", ".NET Framework 4.7 compatible", "net47", Boolean.FALSE) {
+ };
+ static FrameworkStrategy NET_5_0 = new FrameworkStrategy("net5.0", ".NET 5.0 compatible", "net5.0", Boolean.FALSE) {
+ };
+ protected String name;
+ protected String description;
+ protected String testTargetFramework;
+ private Boolean isNetStandard = Boolean.TRUE;
+
+ FrameworkStrategy(String name, String description, String testTargetFramework) {
+ this.name = name;
+ this.description = description;
+ this.testTargetFramework = testTargetFramework;
+ }
+
+ FrameworkStrategy(String name, String description, String testTargetFramework, Boolean isNetStandard) {
+ this.name = name;
+ this.description = description;
+ this.testTargetFramework = testTargetFramework;
+ this.isNetStandard = isNetStandard;
+ }
+
+ protected void configureAdditionalProperties(final Map properties) {
+ properties.putIfAbsent(CodegenConstants.DOTNET_FRAMEWORK, this.name);
+
+ // not intended to be user-settable
+ properties.put(TARGET_FRAMEWORK_IDENTIFIER, this.getTargetFrameworkIdentifier());
+ properties.put(TARGET_FRAMEWORK_VERSION, this.getTargetFrameworkVersion());
+ properties.putIfAbsent(MCS_NET_VERSION_KEY, "4.6-api");
+
+ properties.put(NET_STANDARD, this.isNetStandard);
+ if (properties.containsKey(SUPPORTS_UWP)) {
+ LOGGER.warn(".NET {} generator does not support the UWP option. Use the csharp generator instead.",
+ this.name);
+ properties.remove(SUPPORTS_UWP);
+ }
+ }
+
+ protected String getNugetFrameworkIdentifier() {
+ return this.name.toLowerCase(Locale.ROOT);
+ }
+
+ protected String getTargetFrameworkIdentifier() {
+ if (this.isNetStandard) return ".NETStandard";
+ else return ".NETCoreApp";
+ }
+
+ protected String getTargetFrameworkVersion() {
+ if (this.isNetStandard) return "v" + this.name.replace("netstandard", "");
+ else return "v" + this.name.replace("netcoreapp", "");
+ }
+ }
+
+ protected void configureAdditionalPropertiesForFrameworks(final Map properties, List strategies) {
+ properties.putIfAbsent(CodegenConstants.DOTNET_FRAMEWORK, strategies.stream()
+ .map(p -> p.name)
+ .collect(Collectors.joining(";")));
+
+ // not intended to be user-settable
+ properties.put(TARGET_FRAMEWORK_IDENTIFIER, strategies.stream()
+ .map(p -> p.getTargetFrameworkIdentifier())
+ .collect(Collectors.joining(";")));
+ properties.put(TARGET_FRAMEWORK_VERSION, strategies.stream()
+ .map(p -> p.getTargetFrameworkVersion())
+ .collect(Collectors.joining(";")));
+ properties.putIfAbsent(MCS_NET_VERSION_KEY, "4.6-api");
+
+ properties.put(NET_STANDARD, strategies.stream().anyMatch(p -> Boolean.TRUE.equals(p.isNetStandard)));
+ }
+
+ /**
+ * Return the instantiation type of the property, especially for map and array
+ *
+ * @param schema property schema
+ * @return string presentation of the instantiation type of the property
+ */
+ @Override
+ public String toInstantiationType(Schema schema) {
+ if (ModelUtils.isMapSchema(schema)) {
+ Schema additionalProperties = getAdditionalProperties(schema);
+ String inner = getSchemaType(additionalProperties);
+ if (ModelUtils.isMapSchema(additionalProperties)) {
+ inner = toInstantiationType(additionalProperties);
+ }
+ return instantiationTypes.get("map") + "";
+ } else if (ModelUtils.isArraySchema(schema)) {
+ ArraySchema arraySchema = (ArraySchema) schema;
+ String inner = getSchemaType(arraySchema.getItems());
+ return instantiationTypes.get("array") + "<" + inner + ">";
+ } else {
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Map postProcessModels(Map objs) {
+ objs = super.postProcessModels(objs);
+ List models = (List) objs.get("models");
+
+ // add implements for serializable/parcelable to all models
+ for (Object _mo : models) {
+ Map mo = (Map) _mo;
+ CodegenModel cm = (CodegenModel) mo.get("model");
+
+ if (cm.oneOf != null && !cm.oneOf.isEmpty() && cm.oneOf.contains("ModelNull")) {
+ // if oneOf contains "null" type
+ cm.isNullable = true;
+ cm.oneOf.remove("ModelNull");
+ }
+
+ if (cm.anyOf != null && !cm.anyOf.isEmpty() && cm.anyOf.contains("ModelNull")) {
+ // if anyOf contains "null" type
+ cm.isNullable = true;
+ cm.anyOf.remove("ModelNull");
+ }
+ }
+
+ return objs;
+ }
+
+ @Override
+ public void postProcess() {
+ System.out.println("################################################################################");
+ System.out.println("# Thanks for using OpenAPI Generator. #");
+ System.out.println("# Please consider donation to help us maintain this project \uD83D\uDE4F #");
+ System.out.println("# https://opencollective.com/openapi_generator/donate #");
+ System.out.println("# #");
+ System.out.println("# This generator's contributed by Jim Schubert (https://github.com/jimschubert)#");
+ System.out.println("# Please support his work directly via https://patreon.com/jimschubert \uD83D\uDE4F #");
+ System.out.println("################################################################################");
+ }
+
+ @Override
+ protected void updateModelForObject(CodegenModel m, Schema schema) {
+ /**
+ * we have a custom version of this function so we only set isMap to true if
+ * ModelUtils.isMapSchema
+ * In other generators, isMap is true for all type object schemas
+ */
+ if (schema.getProperties() != null || schema.getRequired() != null && !(schema instanceof ComposedSchema)) {
+ // passing null to allProperties and allRequired as there's no parent
+ addVars(m, unaliasPropertySchema(schema.getProperties()), schema.getRequired(), null, null);
+ }
+ if (ModelUtils.isMapSchema(schema)) {
+ // an object or anyType composed schema that has additionalProperties set
+ addAdditionPropertiesToCodeGenModel(m, schema);
+ } else {
+ m.setIsMap(false);
+ if (ModelUtils.isFreeFormObject(openAPI, schema)) {
+ // non-composed object type with no properties + additionalProperties
+ // additionalProperties must be null, ObjectSchema, or empty Schema
+ addAdditionPropertiesToCodeGenModel(m, schema);
+ }
+ }
+ // process 'additionalProperties'
+ setAddProps(schema, m);
+ }
+}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java
index 0ff2d657e7a..2e77181d7a3 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java
@@ -132,7 +132,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
// reserved word. Ref: https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists#available-keywords
reservedWords = new HashSet<>(
Arrays.asList(
- "abstract", "do", "if", "nil?", "select", "union",
+ "abstract", "annotation", "do", "if", "nil?", "select", "union",
"alias", "else", "in", "of", "self", "unless",
"as", "elsif", "include", "out", "sizeof", "until",
"as?", "end", "instance", "sizeof", "pointerof", "struct", "verbatim",
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CsharpNetcoreFunctionsServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CsharpNetcoreFunctionsServerCodegen.java
new file mode 100644
index 00000000000..8e020f3e641
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CsharpNetcoreFunctionsServerCodegen.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openapitools.codegen.languages;
+
+import org.openapitools.codegen.*;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.Property;
+import io.swagger.models.parameters.Parameter;
+
+import java.io.File;
+import java.util.*;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.openapitools.codegen.meta.GeneratorMetadata;
+import org.openapitools.codegen.meta.Stability;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CsharpNetcoreFunctionsServerCodegen extends CSharpNetCoreReducedClientCodegen {
+ public static final String PROJECT_NAME = "projectName";
+
+ final Logger LOGGER = LoggerFactory.getLogger(CsharpNetcoreFunctionsServerCodegen.class);
+
+ public CodegenType getTag() {
+ return CodegenType.SERVER;
+ }
+
+ public String getName() {
+ return "csharp-netcore-functions";
+ }
+
+ public String getHelp() {
+ return "Generates a csharp server.";
+ }
+
+ public CsharpNetcoreFunctionsServerCodegen() {
+ super();
+
+ generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
+ .stability(Stability.BETA)
+ .build();
+
+ outputFolder = "generated-code" + File.separator + "csharp";
+ modelTemplateFiles.put("model.mustache", ".cs");
+ apiTemplateFiles.put("functions.mustache", ".cs");
+ embeddedTemplateDir = templateDir = "csharp-netcore-functions";
+ apiPackage = "Apis";
+ modelPackage = "Models";
+ String clientPackageDir = "generatedSrc/Client";
+ supportingFiles.add(new SupportingFile("README.mustache", "generatedSrc", "README.md"));
+ supportingFiles.add(new SupportingFile("project.mustache", "generatedSrc", "project.json"));
+
+ supportingFiles.add(new SupportingFile("IApiAccessor.mustache",
+ clientPackageDir, "IApiAccessor.cs"));
+ supportingFiles.add(new SupportingFile("Configuration.mustache",
+ clientPackageDir, "Configuration.cs"));
+ supportingFiles.add(new SupportingFile("ApiClient.mustache",
+ clientPackageDir, "ApiClient.cs"));
+ supportingFiles.add(new SupportingFile("ApiException.mustache",
+ clientPackageDir, "ApiException.cs"));
+ supportingFiles.add(new SupportingFile("ApiResponse.mustache",
+ clientPackageDir, "ApiResponse.cs"));
+ supportingFiles.add(new SupportingFile("ExceptionFactory.mustache",
+ clientPackageDir, "ExceptionFactory.cs"));
+ supportingFiles.add(new SupportingFile("OpenAPIDateConverter.mustache",
+ clientPackageDir, "OpenAPIDateConverter.cs"));
+ }
+
+ @Override
+ public String apiFileFolder() {
+ return outputFolder + File.separator + "generatedSrc" + File.separator + "Functions";
+ }
+
+ @Override
+ public String modelFileFolder() {
+ return outputFolder + File.separator + "generatedSrc" + File.separator + "Models";
+ }
+
+ @Override
+ public String apiDocFileFolder() {
+ return (outputFolder + "/Docs").replace('/', File.separatorChar);
+ }
+
+ @Override
+ public String apiTestFileFolder() {
+ return outputFolder + File.separator + "Tests" + File.separator + "Tests" + File.separator + apiPackage();
+ }
+
+}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java
index 9acfe364003..5f438eb6f8b 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java
@@ -323,6 +323,21 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
// enums are generated with built_value and make use of BuiltSet
model.imports.add("BuiltSet");
}
+
+ if (property.isContainer) {
+ // Figure out if there are any container type additionalProperties
+ // that need a custom serializer builder factory added.
+ final CodegenProperty items = property.items;
+ if (items.getAdditionalProperties() != null) {
+ addBuiltValueSerializer(new BuiltValueSerializer(
+ items.isArray,
+ items.getUniqueItems(),
+ items.isMap,
+ items.items.isNullable,
+ items.getAdditionalProperties().dataType
+ ));
+ }
+ }
}
}
@@ -332,7 +347,6 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
Map operations = (Map) objs.get("operations");
List operationList = (List) operations.get("operation");
- Set> serializers = new HashSet<>();
Set resultImports = new HashSet<>();
for (CodegenOperation op : operationList) {
@@ -370,12 +384,13 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
// Generate serializer factories for all container type parameters.
// But skip binary and file parameters, JSON serializers don't make sense there.
if (param.isContainer && !(param.isBinary || param.isFile )) {
- final Map serializer = new HashMap<>();
- serializer.put("isArray", param.isArray);
- serializer.put("uniqueItems", param.uniqueItems);
- serializer.put("isMap", param.isMap);
- serializer.put("baseType", param.baseType);
- serializers.add(serializer);
+ addBuiltValueSerializer(new BuiltValueSerializer(
+ param.isArray,
+ param.uniqueItems,
+ param.isMap,
+ param.items.isNullable,
+ param.baseType
+ ));
}
}
@@ -387,17 +402,17 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
// Generate serializer factories for response types.
// But skip binary and file response, JSON serializers don't make sense there.
if (op.returnContainer != null && !(op.isResponseBinary || op.isResponseFile)) {
- final Map serializer = new HashMap<>();
- serializer.put("isArray", Objects.equals("array", op.returnContainer) || Objects.equals("set", op.returnContainer));
- serializer.put("uniqueItems", op.uniqueItems);
- serializer.put("isMap", Objects.equals("map", op.returnContainer));
- serializer.put("baseType", op.returnBaseType);
- serializers.add(serializer);
+ addBuiltValueSerializer(new BuiltValueSerializer(
+ Objects.equals("array", op.returnContainer) || Objects.equals("set", op.returnContainer),
+ op.uniqueItems,
+ Objects.equals("map", op.returnContainer),
+ false,
+ op.returnBaseType
+ ));
}
}
objs.put("imports", resultImports.stream().sorted().collect(Collectors.toList()));
- objs.put("serializers", serializers);
return objs;
}
@@ -410,6 +425,19 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
});
}
+ /**
+ * Adds the serializer to the global list of custom built_value serializers.
+ * @param serializer
+ */
+ private void addBuiltValueSerializer(BuiltValueSerializer serializer) {
+ System.out.println("######## Add serializer!");
+ additionalProperties.compute("builtValueSerializers", (k, v) -> {
+ Set serializers = v == null ? Sets.newHashSet() : ((Set) v);
+ serializers.add(serializer);
+ return serializers;
+ });
+ }
+
private Set rewriteImports(Set originalImports, boolean isModel) {
Set resultImports = Sets.newHashSet();
for (String modelImport : originalImports) {
@@ -428,4 +456,58 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
}
return resultImports;
}
+
+ static class BuiltValueSerializer {
+
+ final boolean isArray;
+
+ final boolean uniqueItems;
+
+ final boolean isMap;
+
+ final boolean isNullable;
+
+ final String dataType;
+
+ private BuiltValueSerializer(boolean isArray, boolean uniqueItems, boolean isMap, boolean isNullable, String dataType) {
+ this.isArray = isArray;
+ this.uniqueItems = uniqueItems;
+ this.isMap = isMap;
+ this.isNullable = isNullable;
+ this.dataType = dataType;
+ }
+
+ public boolean isArray() {
+ return isArray;
+ }
+
+ public boolean isUniqueItems() {
+ return uniqueItems;
+ }
+
+ public boolean isMap() {
+ return isMap;
+ }
+
+ public boolean isNullable() {
+ return isNullable;
+ }
+
+ public String getDataType() {
+ return dataType;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BuiltValueSerializer that = (BuiltValueSerializer) o;
+ return isArray == that.isArray && uniqueItems == that.uniqueItems && isMap == that.isMap && isNullable == that.isNullable && dataType.equals(that.dataType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(isArray, uniqueItems, isMap, isNullable, dataType);
+ }
+ }
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java
index 9903908d4e0..62c9d6dcc5f 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java
@@ -613,7 +613,7 @@ public class ElixirClientCodegen extends DefaultCodegen implements CodegenConfig
return "%{}";
}
// Primitive return type, don't even try to decode
- if (baseType == null || (simpleType && primitiveType)) {
+ if (baseType == null || (containerType == null && primitiveType)) {
return "false";
} else if (isArray && languageSpecificPrimitives().contains(baseType)) {
return "[]";
@@ -733,16 +733,13 @@ public class ElixirClientCodegen extends DefaultCodegen implements CodegenConfig
StringBuilder returnEntry = new StringBuilder();
if (exResponse.baseType == null) {
returnEntry.append("nil");
- } else if (exResponse.simpleType) {
+ } else if (exResponse.containerType == null) { // not container (array, map, set)
if (!exResponse.primitiveType) {
returnEntry.append(moduleName);
returnEntry.append(".Model.");
}
returnEntry.append(exResponse.baseType);
returnEntry.append(".t");
- } else if (exResponse.containerType == null) {
- returnEntry.append(returnBaseType);
- returnEntry.append(".t");
} else {
if (exResponse.containerType.equals("array") ||
exResponse.containerType.equals("set")) {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java
index 0d9266020ac..965da6dbd77 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java
@@ -80,6 +80,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
public static final String JERSEY2 = "jersey2";
public static final String NATIVE = "native";
public static final String OKHTTP_GSON = "okhttp-gson";
+ public static final String OKHTTP_GSON_NEXTGEN = "okhttp-gson-nextgen";
public static final String RESTEASY = "resteasy";
public static final String RESTTEMPLATE = "resttemplate";
public static final String WEBCLIENT = "webclient";
@@ -168,6 +169,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
supportedLibraries.put(JERSEY2, "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.9.x");
supportedLibraries.put(FEIGN, "HTTP client: OpenFeign 10.x. JSON processing: Jackson 2.9.x.");
supportedLibraries.put(OKHTTP_GSON, "[DEFAULT] HTTP client: OkHttp 3.x. JSON processing: Gson 2.8.x. Enable Parcelable models on Android using '-DparcelableModel=true'. Enable gzip request encoding using '-DuseGzipFeature=true'.");
+ supportedLibraries.put(OKHTTP_GSON_NEXTGEN, "HTTP client: OkHttp 3.x. JSON processing: Gson 2.8.x.'. Better support for oneOf/anyOf with breaking changes. Will replace `okhttp-gson` in the 6.0.0 release.");
supportedLibraries.put(RETROFIT_2, "HTTP client: OkHttp 3.x. JSON processing: Gson 2.x (Retrofit 2.3.0). Enable the RxJava adapter using '-DuseRxJava[2/3]=true'. (RxJava 1.x or 2.x or 3.x)");
supportedLibraries.put(RESTTEMPLATE, "HTTP client: Spring RestTemplate 4.x. JSON processing: Jackson 2.9.x");
supportedLibraries.put(WEBCLIENT, "HTTP client: Spring WebClient 5.x. JSON processing: Jackson 2.9.x");
@@ -423,7 +425,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
supportingFiles.add(new SupportingFile("ParamExpander.mustache", invokerFolder, "ParamExpander.java"));
supportingFiles.add(new SupportingFile("EncodingUtils.mustache", invokerFolder, "EncodingUtils.java"));
supportingFiles.add(new SupportingFile("auth/DefaultApi20Impl.mustache", authFolder, "DefaultApi20Impl.java"));
- } else if (OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) {
+ } else if (OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary()) || OKHTTP_GSON_NEXTGEN.equals(getLibrary())) {
// the "okhttp-gson" library template requires "ApiCallback.mustache" for async call
supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java"));
supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java"));
@@ -431,6 +433,9 @@ public class JavaClientCodegen extends AbstractJavaCodegen
supportingFiles.add(new SupportingFile("ProgressRequestBody.mustache", invokerFolder, "ProgressRequestBody.java"));
supportingFiles.add(new SupportingFile("ProgressResponseBody.mustache", invokerFolder, "ProgressResponseBody.java"));
supportingFiles.add(new SupportingFile("GzipRequestInterceptor.mustache", invokerFolder, "GzipRequestInterceptor.java"));
+ if (OKHTTP_GSON_NEXTGEN.equals(getLibrary())) {
+ supportingFiles.add(new SupportingFile("AbstractOpenApiSchema.mustache", modelsFolder, "AbstractOpenApiSchema.java"));
+ }
// NOTE: below moved to postProcessOperationsWithModels
//supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
@@ -615,7 +620,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
// has OAuth defined
if (ProcessUtils.hasOAuthMethods(openAPI)) {
// for okhttp-gson (default), check to see if OAuth is defined and included OAuth-related files accordingly
- if ((OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary()))) {
+ if ((OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) || OKHTTP_GSON_NEXTGEN.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
supportingFiles.add(new SupportingFile("auth/RetryingOAuth.mustache", authFolder, "RetryingOAuth.java"));
}
@@ -916,7 +921,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
CodegenModel cm = (CodegenModel) mo.get("model");
cm.getVendorExtensions().putIfAbsent("x-implements", new ArrayList());
- if (JERSEY2.equals(getLibrary()) || NATIVE.equals(getLibrary())) {
+ if (JERSEY2.equals(getLibrary()) || NATIVE.equals(getLibrary()) || OKHTTP_GSON_NEXTGEN.equals(getLibrary())) {
cm.getVendorExtensions().put("x-implements", new ArrayList());
if (cm.oneOf != null && !cm.oneOf.isEmpty() && cm.oneOf.contains("ModelNull")) {
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
index 91e3ce32c3f..28a3853332d 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java
@@ -49,6 +49,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
public static final String USE_RX_JAVA3 = "useRxJava3";
public static final String USE_COROUTINES = "useCoroutines";
public static final String DO_NOT_USE_RX_AND_COROUTINES = "doNotUseRxAndCoroutines";
+ public static final String OMIT_GRADLE_PLUGIN_VERSIONS = "omitGradlePluginVersions";
public static final String DATE_LIBRARY = "dateLibrary";
public static final String REQUEST_DATE_CONVERTER = "requestDateConverter";
@@ -201,6 +202,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
cliOptions.add(CliOption.newBoolean(USE_RX_JAVA2, "Whether to use the RxJava2 adapter with the retrofit2 library. IMPORTANT: this option has been deprecated. Please use `useRxJava3` instead."));
cliOptions.add(CliOption.newBoolean(USE_RX_JAVA3, "Whether to use the RxJava3 adapter with the retrofit2 library."));
cliOptions.add(CliOption.newBoolean(USE_COROUTINES, "Whether to use the Coroutines adapter with the retrofit2 library."));
+ cliOptions.add(CliOption.newBoolean(OMIT_GRADLE_PLUGIN_VERSIONS, "Whether to declare Gradle plugin versions in build files."));
cliOptions.add(CliOption.newBoolean(MOSHI_CODE_GEN, "Whether to enable codegen with the Moshi library. Refer to the [official Moshi doc](https://github.com/square/moshi#codegen) for more info."));
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java
index f04a58fcf42..5f55e9d47f0 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ProtobufSchemaCodegen.java
@@ -47,10 +47,18 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
private static final String IMPORTS = "imports";
+ public static final String NUMBERED_FIELD_NUMBER_LIST = "numberedFieldNumberList";
+
+ public static final String START_ENUMS_WITH_UNKNOWN = "startEnumsWithUnknown";
+
private final Logger LOGGER = LoggerFactory.getLogger(ProtobufSchemaCodegen.class);
protected String packageName = "openapitools";
+ private boolean numberedFieldNumberList = false;
+
+ private boolean startEnumsWithUnknown = false;
+
@Override
public CodegenType getTag() {
return CodegenType.SCHEMA;
@@ -145,6 +153,8 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
cliOptions.clear();
+ addSwitch(NUMBERED_FIELD_NUMBER_LIST, "Field numbers in order.", numberedFieldNumberList);
+ addSwitch(START_ENUMS_WITH_UNKNOWN, "Introduces \"UNKNOWN\" as the first element of enumerations.", startEnumsWithUnknown);
}
@Override
@@ -164,6 +174,14 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
}
+ if (additionalProperties.containsKey(this.NUMBERED_FIELD_NUMBER_LIST)) {
+ this.numberedFieldNumberList = convertPropertyToBooleanAndWriteBack(NUMBERED_FIELD_NUMBER_LIST);
+ }
+
+ if (additionalProperties.containsKey(this.START_ENUMS_WITH_UNKNOWN)) {
+ this.startEnumsWithUnknown = convertPropertyToBooleanAndWriteBack(START_ENUMS_WITH_UNKNOWN);
+ }
+
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
}
@@ -183,6 +201,34 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
return camelize(sanitizeName(operationId));
}
+ public void addUnknownToAllowableValues(Map allowableValues, String name) {
+ if(startEnumsWithUnknown) {
+ if(allowableValues.containsKey("enumVars")) {
+ List> enumVars = (List>)allowableValues.get("enumVars");
+
+ HashMap unknown = new HashMap();
+ unknown.put("name", name + "_UNKNOWN");
+ unknown.put("isString", "false");
+ unknown.put("value", "\"" + name + "_UNKNOWN\"");
+
+ enumVars.add(0, unknown);
+ }
+
+ if(allowableValues.containsKey("values")) {
+ List values = (List)allowableValues.get("values");
+ values.add(0, name + "_UNKNOWN");
+ }
+ }
+ }
+
+ public void addEnumIndexes(List> enumVars) {
+ int enumIndex = 0;
+ for (Map enumVar : enumVars) {
+ enumVar.put("protobuf-enum-index", enumIndex);
+ enumIndex++;
+ }
+ }
+
@Override
public Map postProcessModels(Map objs) {
objs = postProcessModelsEnum(objs);
@@ -192,6 +238,17 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
Map mo = (Map) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
+ if(cm.isEnum) {
+ Map allowableValues = cm.getAllowableValues();
+ addUnknownToAllowableValues(allowableValues, cm.getClassname());
+
+ if (allowableValues.containsKey("enumVars")) {
+ List> enumVars = (List>)allowableValues.get("enumVars");
+ addEnumIndexes(enumVars);
+ }
+ }
+
+ int index = 1;
for (CodegenProperty var : cm.vars) {
// add x-protobuf-type: repeated if it's an array
if (Boolean.TRUE.equals(var.isArray)) {
@@ -208,21 +265,27 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
}
}
- if (var.isEnum && var.allowableValues.containsKey("enumVars")) {
- List> enumVars = (List>) var.allowableValues.get("enumVars");
- int enumIndex = 0;
- for (Map enumVar : enumVars) {
- enumVar.put("protobuf-enum-index", enumIndex);
- enumIndex++;
+ if (var.isEnum) {
+ addUnknownToAllowableValues(var.allowableValues, var.getEnumName());
+
+ if(var.allowableValues.containsKey("enumVars")) {
+ List> enumVars = (List>) var.allowableValues.get("enumVars");
+ addEnumIndexes(enumVars);
}
}
// Add x-protobuf-index, unless already specified
- try {
- var.vendorExtensions.putIfAbsent("x-protobuf-index", generateFieldNumberFromString(var.getName()));
- } catch (ProtoBufIndexComputationException e) {
- LOGGER.error("Exception when assigning a index to a protobuf field", e);
- var.vendorExtensions.putIfAbsent("x-protobuf-index", "Generated field number is in reserved range (19000, 19999)");
+ if(this.numberedFieldNumberList) {
+ var.vendorExtensions.putIfAbsent("x-protobuf-index", index);
+ index++;
+ }
+ else {
+ try {
+ var.vendorExtensions.putIfAbsent("x-protobuf-index", generateFieldNumberFromString(var.getName()));
+ } catch (ProtoBufIndexComputationException e) {
+ LOGGER.error("Exception when assigning a index to a protobuf field", e);
+ var.vendorExtensions.putIfAbsent("x-protobuf-index", "Generated field number is in reserved range (19000, 19999)");
+ }
}
}
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java
index 138b1c54356..05b5b92df39 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonLegacyClientCodegen.java
@@ -215,6 +215,9 @@ public class PythonLegacyClientCodegen extends AbstractPythonCodegen implements
}
}
+ String modelPath = packagePath() + File.separatorChar + modelPackage.replace('.', File.separatorChar);
+ String apiPath = packagePath() + File.separatorChar + apiPackage.replace('.', File.separatorChar);
+
String readmePath = "README.md";
String readmeTemplate = "README.mustache";
if (generateSourceCodeOnly) {
@@ -237,8 +240,8 @@ public class PythonLegacyClientCodegen extends AbstractPythonCodegen implements
}
supportingFiles.add(new SupportingFile("configuration.mustache", packagePath(), "configuration.py"));
supportingFiles.add(new SupportingFile("__init__package.mustache", packagePath(), "__init__.py"));
- supportingFiles.add(new SupportingFile("__init__model.mustache", packagePath() + File.separatorChar + modelPackage, "__init__.py"));
- supportingFiles.add(new SupportingFile("__init__api.mustache", packagePath() + File.separatorChar + apiPackage, "__init__.py"));
+ supportingFiles.add(new SupportingFile("__init__model.mustache", modelPath, "__init__.py"));
+ supportingFiles.add(new SupportingFile("__init__api.mustache", apiPath, "__init__.py"));
// If the package name consists of dots(openapi.client), then we need to create the directory structure like openapi/client with __init__ files.
String[] packageNameSplits = packageName.split("\\.");
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RubyClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RubyClientCodegen.java
index f7d5a20e079..335a329ef59 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RubyClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RubyClientCodegen.java
@@ -141,10 +141,10 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
defaultValue("unlicense"));
cliOptions.add(new CliOption(GEM_REQUIRED_RUBY_VERSION, "gem required Ruby version. ").
- defaultValue(">= 1.9"));
+ defaultValue(">= 2.4"));
cliOptions.add(new CliOption(GEM_HOMEPAGE, "gem homepage. ").
- defaultValue("http://org.openapitools"));
+ defaultValue("https://openapi-generator.tech"));
cliOptions.add(new CliOption(GEM_SUMMARY, "gem summary. ").
defaultValue("A ruby wrapper for the REST APIs"));
@@ -152,7 +152,7 @@ public class RubyClientCodegen extends AbstractRubyCodegen {
cliOptions.add(new CliOption(GEM_DESCRIPTION, "gem description. ").
defaultValue("This gem maps to a REST API"));
- cliOptions.add(new CliOption(GEM_AUTHOR, "gem author (only one is supported)."));
+ cliOptions.add(new CliOption(GEM_AUTHOR, "gem author (only one is supported).").defaultValue("OpenAPI-Generator"));
cliOptions.add(new CliOption(GEM_AUTHOR_EMAIL, "gem author email (only one is supported)."));
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java
index 31614ac9b65..2cd6ebd8dd4 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java
@@ -66,6 +66,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
public static final String SWIFT_PACKAGE_PATH = "swiftPackagePath";
public static final String USE_CLASSES = "useClasses";
public static final String USE_BACKTICK_ESCAPES = "useBacktickEscapes";
+ public static final String GENERATE_FROZEN_ENUMS = "generateFrozenEnums";
public static final String GENERATE_MODEL_ADDITIONAL_PROPERTIES = "generateModelAdditionalProperties";
public static final String HASHABLE_MODELS = "hashableModels";
public static final String MAP_FILE_BINARY_TO_DATA = "mapFileBinaryToData";
@@ -90,6 +91,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
protected boolean useClasses = false;
protected boolean useBacktickEscapes = false;
protected boolean generateModelAdditionalProperties = true;
+ protected boolean generateFrozenEnums = true;
protected boolean hashableModels = true;
protected boolean mapFileBinaryToData = false;
protected String[] responseAs = new String[0];
@@ -281,6 +283,9 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
cliOptions.add(new CliOption(USE_BACKTICK_ESCAPES,
"Escape reserved words using backticks (default: false)")
.defaultValue(Boolean.FALSE.toString()));
+ cliOptions.add(new CliOption(GENERATE_FROZEN_ENUMS,
+ "Generate frozen enums (default: true)")
+ .defaultValue(Boolean.TRUE.toString()));
cliOptions.add(new CliOption(GENERATE_MODEL_ADDITIONAL_PROPERTIES,
"Generate model additional properties (default: true)")
.defaultValue(Boolean.TRUE.toString()));
@@ -485,6 +490,13 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
setUseBacktickEscapes(convertPropertyToBooleanAndWriteBack(USE_BACKTICK_ESCAPES));
}
+ // Setup generateFrozenEnums option. If true, enums will strictly include
+ // cases matching the spec. If false, enums will also include an extra catch-all case.
+ if (additionalProperties.containsKey(GENERATE_FROZEN_ENUMS)) {
+ setGenerateFrozenEnums(convertPropertyToBooleanAndWriteBack(GENERATE_FROZEN_ENUMS));
+ }
+ additionalProperties.put(GENERATE_FROZEN_ENUMS, generateFrozenEnums);
+
if (additionalProperties.containsKey(GENERATE_MODEL_ADDITIONAL_PROPERTIES)) {
setGenerateModelAdditionalProperties(convertPropertyToBooleanAndWriteBack(GENERATE_MODEL_ADDITIONAL_PROPERTIES));
}
@@ -943,6 +955,10 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
this.useBacktickEscapes = useBacktickEscapes;
}
+ public void setGenerateFrozenEnums(boolean generateFrozenEnums) {
+ this.generateFrozenEnums = generateFrozenEnums;
+ }
+
public void setGenerateModelAdditionalProperties(boolean generateModelAdditionalProperties) {
this.generateModelAdditionalProperties = generateModelAdditionalProperties;
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java
index 758f2650f5a..d2ab116ab1e 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java
@@ -67,7 +67,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
public static final String STRING_ENUMS_DESC = "Generate string enums instead of objects for enum values.";
public static final String QUERY_PARAM_OBJECT_FORMAT = "queryParamObjectFormat";
- protected String ngVersion = "12.2.12";
+ protected String ngVersion = "13.0.1";
protected String npmRepository = null;
private boolean useSingleRequestParameter = false;
protected String serviceSuffix = "Service";
@@ -146,7 +146,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
@Override
public String getHelp() {
- return "Generates a TypeScript Angular (6.x - 12.x) client library.";
+ return "Generates a TypeScript Angular (6.x - 13.x) client library.";
}
@Override
@@ -243,7 +243,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
} else {
additionalProperties.put(DELETE_ACCEPTS_BODY, false);
}
-
+
additionalProperties.put(NG_VERSION, ngVersion);
if (additionalProperties.containsKey(API_MODULE_PREFIX)) {
@@ -300,7 +300,9 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
}
// Set the typescript version compatible to the Angular version
- if (ngVersion.atLeast("12.0.0")) {
+ if (ngVersion.atLeast("13.0.0")) {
+ additionalProperties.put("tsVersion", ">=4.4.2 <4.5.0");
+ } else if (ngVersion.atLeast("12.0.0")) {
additionalProperties.put("tsVersion", ">=4.3.0 <4.4.0");
} else if (ngVersion.atLeast("11.0.0")) {
additionalProperties.put("tsVersion", ">=4.0.0 <4.1.0");
@@ -318,7 +320,9 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
}
// Set the rxJS version compatible to the Angular version
- if (ngVersion.atLeast("10.0.0")) {
+ if (ngVersion.atLeast("13.0.0")) {
+ additionalProperties.put("rxjsVersion", "7.4.0");
+ } else if (ngVersion.atLeast("10.0.0")) {
additionalProperties.put("rxjsVersion", "6.6.0");
} else if (ngVersion.atLeast("9.0.0")) {
additionalProperties.put("rxjsVersion", "6.5.3");
@@ -334,7 +338,10 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
supportingFiles.add(new SupportingFile("ng-package.mustache", getIndexDirectory(), "ng-package.json"));
// Specific ng-packagr configuration
- if (ngVersion.atLeast("12.0.0")) {
+ if (ngVersion.atLeast("13.0.0")) {
+ additionalProperties.put("ngPackagrVersion", "13.0.3");
+ additionalProperties.put("tsickleVersion", "0.43.0");
+ } else if (ngVersion.atLeast("12.0.0")) {
additionalProperties.put("ngPackagrVersion", "12.2.1");
additionalProperties.put("tsickleVersion", "0.43.0");
} else if (ngVersion.atLeast("11.0.0")) {
@@ -542,8 +549,19 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
setChildDiscriminatorValue(cm, child);
}
}
+
+ // with tagged union, a child model doesn't extend the parent (all properties are just copied over)
+ // it means we don't need to import that parent any more
if (cm.parent != null) {
cm.imports.remove(cm.parent);
+
+ // however, it's possible that the child model contains a recursive reference to the parent
+ // in order to support this case, we update the list of imports from properties once again
+ for (CodegenProperty cp: cm.allVars) {
+ addImportsForPropertyType(cm, cp);
+ }
+ removeSelfReferenceImports(cm);
+
}
}
// Add additional filename information for imports
diff --git a/modules/openapi-generator/src/main/resources/C-libcurl/CMakeLists.txt.mustache b/modules/openapi-generator/src/main/resources/C-libcurl/CMakeLists.txt.mustache
index 7ff01b17c0e..8d2ef17609c 100644
--- a/modules/openapi-generator/src/main/resources/C-libcurl/CMakeLists.txt.mustache
+++ b/modules/openapi-generator/src/main/resources/C-libcurl/CMakeLists.txt.mustache
@@ -28,7 +28,11 @@ else()
endif()
set(pkgName "{{projectName}}")
-set(VERSION 0.0.1) # this default version can be overridden in PreTarget.cmake
+
+# this default version can be overridden in PreTarget.cmake
+set(PROJECT_VERSION_MAJOR 0)
+set(PROJECT_VERSION_MINOR 0)
+set(PROJECT_VERSION_PATCH 1)
find_package(CURL 7.58.0 REQUIRED)
if(CURL_FOUND)
@@ -84,6 +88,8 @@ set(HDRS
include(PreTarget.cmake OPTIONAL)
+set(PROJECT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+
# Add library with project file with project name as library name
add_library(${pkgName} ${SRCS} ${HDRS})
# Link dependent libraries
@@ -100,22 +106,22 @@ include(PostTarget.cmake OPTIONAL)
# installation of libraries, headers, and config files
if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in)
- install(TARGETS ${pkgName} DESTINATION ${CMAKE_INSTALL_PREFIX})
+ install(TARGETS ${pkgName} DESTINATION lib)
else()
include(GNUInstallDirs)
- install(TARGETS ${pkgName} DESTINATION ${CMAKE_INSTALL_PREFIX} EXPORT ${pkgName}Targets)
+ install(TARGETS ${pkgName} DESTINATION lib EXPORT ${pkgName}Targets)
foreach(HDR_FILE ${HDRS})
get_filename_component(HDR_DIRECTORY ${HDR_FILE} DIRECTORY)
get_filename_component(ABSOLUTE_HDR_DIRECTORY ${HDR_DIRECTORY} ABSOLUTE)
file(RELATIVE_PATH RELATIVE_HDR_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${ABSOLUTE_HDR_DIRECTORY})
- install(FILES ${HDR_FILE} DESTINATION include/${RELATIVE_HDR_PATH})
+ install(FILES ${HDR_FILE} DESTINATION include/${pkgName}/${RELATIVE_HDR_PATH})
endforeach()
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${pkgName}/${pkgName}ConfigVersion.cmake"
- VERSION "${VERSION}"
+ VERSION "${PROJECT_VERSION_STRING}"
COMPATIBILITY AnyNewerVersion
)
@@ -147,6 +153,9 @@ else()
)
endif()
+# make installation packages
+include(Packing.cmake OPTIONAL)
+
# Setting file variables to null
set(SRCS "")
set(HDRS "")
diff --git a/modules/openapi-generator/src/main/resources/C-libcurl/Packing.cmake.mustache b/modules/openapi-generator/src/main/resources/C-libcurl/Packing.cmake.mustache
new file mode 100644
index 00000000000..15bd4c8d5e9
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/C-libcurl/Packing.cmake.mustache
@@ -0,0 +1,24 @@
+set(CPACK_PACKAGE_NAME lib${pkgName})
+
+set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
+
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_PACKAGE_DESCRIPTION_SUMMARY})
+set(CPACK_PACKAGE_VENDOR ${PROJECT_PACKAGE_VENDOR})
+set(CPACK_PACKAGE_CONTACT ${PROJECT_PACKAGE_CONTACT})
+set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${PROJECT_PACKAGE_MAINTAINER})
+
+set(CPACK_VERBATIM_VARIABLES YES)
+
+set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
+
+set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
+
+set(CPACK_DEB_COMPONENT_INSTALL YES)
+
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS TRUE)
+
+include(CPack)
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/native/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/native/api.mustache
index 018f51b32ce..218a432d106 100644
--- a/modules/openapi-generator/src/main/resources/Java/libraries/native/api.mustache
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/native/api.mustache
@@ -222,14 +222,25 @@ public class {{classname}} {
if (memberVarResponseInterceptor != null) {
memberVarResponseInterceptor.accept(localVarResponse);
}
- if (localVarResponse.statusCode()/ 100 != 2) {
- throw getApiException("{{operationId}}", localVarResponse);
- }
- return new ApiResponse<{{{returnType}}}{{^returnType}}Void{{/returnType}}>(
+ try {
+ if (localVarResponse.statusCode()/ 100 != 2) {
+ throw getApiException("{{operationId}}", localVarResponse);
+ }
+ return new ApiResponse<{{{returnType}}}{{^returnType}}Void{{/returnType}}>(
localVarResponse.statusCode(),
localVarResponse.headers().map(),
- {{#returnType}}memberVarObjectMapper.readValue(localVarResponse.body(), new TypeReference<{{{returnType}}}>() {}){{/returnType}}{{^returnType}}null{{/returnType}}
+ {{#returnType}}memberVarObjectMapper.readValue(localVarResponse.body(), new TypeReference<{{{returnType}}}>() {}) // closes the InputStream{{/returnType}}
+ {{^returnType}}null{{/returnType}}
);
+ } finally {
+ {{^returnType}}
+ // Drain the InputStream
+ while (localVarResponse.body().read() != -1) {
+ // Ignore
+ }
+ localVarResponse.body().close();
+ {{/returnType}}
+ }
} catch (IOException e) {
throw new ApiException(e);
}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/AbstractOpenApiSchema.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/AbstractOpenApiSchema.mustache
new file mode 100644
index 00000000000..3ba02e44c0e
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/AbstractOpenApiSchema.mustache
@@ -0,0 +1,138 @@
+{{>licenseInfo}}
+
+package {{modelPackage}};
+
+import {{invokerPackage}}.ApiException;
+import java.util.Objects;
+import java.lang.reflect.Type;
+import java.util.Map;
+import javax.ws.rs.core.GenericType;
+
+//import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * Abstract class for oneOf,anyOf schemas defined in OpenAPI spec
+ */
+{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}
+public abstract class AbstractOpenApiSchema {
+
+ // store the actual instance of the schema/object
+ private Object instance;
+
+ // is nullable
+ private Boolean isNullable;
+
+ // schema type (e.g. oneOf, anyOf)
+ private final String schemaType;
+
+ public AbstractOpenApiSchema(String schemaType, Boolean isNullable) {
+ this.schemaType = schemaType;
+ this.isNullable = isNullable;
+ }
+
+ /**
+ * Get the list of oneOf/anyOf composed schemas allowed to be stored in this object
+ *
+ * @return an instance of the actual schema/object
+ */
+ public abstract Map getSchemas();
+
+ /**
+ * Get the actual instance
+ *
+ * @return an instance of the actual schema/object
+ */
+ //@JsonValue
+ public Object getActualInstance() {return instance;}
+
+ /**
+ * Set the actual instance
+ *
+ * @param instance the actual instance of the schema/object
+ */
+ public void setActualInstance(Object instance) {this.instance = instance;}
+
+ /**
+ * Get the instant recursively when the schemas defined in oneOf/anyof happen to be oneOf/anyOf schema as well
+ *
+ * @return an instance of the actual schema/object
+ */
+ public Object getActualInstanceRecursively() {
+ return getActualInstanceRecursively(this);
+ }
+
+ private Object getActualInstanceRecursively(AbstractOpenApiSchema object) {
+ if (object.getActualInstance() == null) {
+ return null;
+ } else if (object.getActualInstance() instanceof AbstractOpenApiSchema) {
+ return getActualInstanceRecursively((AbstractOpenApiSchema)object.getActualInstance());
+ } else {
+ return object.getActualInstance();
+ }
+ }
+
+ /**
+ * Get the schema type (e.g. anyOf, oneOf)
+ *
+ * @return the schema type
+ */
+ public String getSchemaType() {
+ return schemaType;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class ").append(getClass()).append(" {\n");
+ sb.append(" instance: ").append(toIndentedString(instance)).append("\n");
+ sb.append(" isNullable: ").append(toIndentedString(isNullable)).append("\n");
+ sb.append(" schemaType: ").append(toIndentedString(schemaType)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ AbstractOpenApiSchema a = (AbstractOpenApiSchema) o;
+ return Objects.equals(this.instance, a.instance) &&
+ Objects.equals(this.isNullable, a.isNullable) &&
+ Objects.equals(this.schemaType, a.schemaType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(instance, isNullable, schemaType);
+ }
+
+ /**
+ * Is nullable
+ *
+ * @return true if it's nullable
+ */
+ public Boolean isNullable() {
+ if (Boolean.TRUE.equals(isNullable)) {
+ return Boolean.TRUE;
+ } else {
+ return Boolean.FALSE;
+ }
+ }
+
+{{>libraries/jersey2/additional_properties}}
+
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiCallback.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiCallback.mustache
new file mode 100644
index 00000000000..53b6a7b8e34
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiCallback.mustache
@@ -0,0 +1,51 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+import java.io.IOException;
+
+import java.util.Map;
+import java.util.List;
+
+/**
+ * Callback for asynchronous API call.
+ *
+ * @param The return type
+ */
+public interface ApiCallback {
+ /**
+ * This is called when the API call fails.
+ *
+ * @param e The exception causing the failure
+ * @param statusCode Status code of the response if available, otherwise it would be 0
+ * @param responseHeaders Headers of the response if available, otherwise it would be null
+ */
+ void onFailure(ApiException e, int statusCode, Map> responseHeaders);
+
+ /**
+ * This is called when the API call succeeded.
+ *
+ * @param result The result deserialized from response
+ * @param statusCode Status code of the response
+ * @param responseHeaders Headers of the response
+ */
+ void onSuccess(T result, int statusCode, Map> responseHeaders);
+
+ /**
+ * This is called when the API upload processing.
+ *
+ * @param bytesWritten bytes Written
+ * @param contentLength content length of request body
+ * @param done write end
+ */
+ void onUploadProgress(long bytesWritten, long contentLength, boolean done);
+
+ /**
+ * This is called when the API download processing.
+ *
+ * @param bytesRead bytes Read
+ * @param contentLength content length of the response
+ * @param done Read end
+ */
+ void onDownloadProgress(long bytesRead, long contentLength, boolean done);
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiClient.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiClient.mustache
new file mode 100644
index 00000000000..732551cec58
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiClient.mustache
@@ -0,0 +1,1737 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+{{#dynamicOperations}}
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.PathItem;
+import io.swagger.v3.oas.models.parameters.Parameter;
+import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum;
+import io.swagger.v3.parser.OpenAPIV3Parser;
+{{/dynamicOperations}}
+import okhttp3.*;
+import okhttp3.internal.http.HttpMethod;
+import okhttp3.internal.tls.OkHostnameVerifier;
+import okhttp3.logging.HttpLoggingInterceptor;
+import okhttp3.logging.HttpLoggingInterceptor.Level;
+import okio.Buffer;
+import okio.BufferedSink;
+import okio.Okio;
+{{#joda}}
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+{{/joda}}
+{{#threetenbp}}
+import org.threeten.bp.LocalDate;
+import org.threeten.bp.OffsetDateTime;
+import org.threeten.bp.format.DateTimeFormatter;
+{{/threetenbp}}
+{{#hasOAuthMethods}}
+import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+{{/hasOAuthMethods}}
+
+import javax.net.ssl.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+{{#java8}}
+import java.time.LocalDate;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+{{/java8}}
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import {{invokerPackage}}.auth.Authentication;
+import {{invokerPackage}}.auth.HttpBasicAuth;
+import {{invokerPackage}}.auth.HttpBearerAuth;
+import {{invokerPackage}}.auth.ApiKeyAuth;
+{{#hasOAuthMethods}}
+import {{invokerPackage}}.auth.OAuth;
+import {{invokerPackage}}.auth.RetryingOAuth;
+import {{invokerPackage}}.auth.OAuthFlow;
+{{/hasOAuthMethods}}
+
+/**
+ * ApiClient class.
+ */
+public class ApiClient {
+
+ private String basePath = "{{{basePath}}}";
+ private boolean debugging = false;
+ private Map defaultHeaderMap = new HashMap();
+ private Map defaultCookieMap = new HashMap();
+ private String tempFolderPath = null;
+
+ private Map authentications;
+
+ private DateFormat dateFormat;
+ private DateFormat datetimeFormat;
+ private boolean lenientDatetimeFormat;
+ private int dateLength;
+
+ private InputStream sslCaCert;
+ private boolean verifyingSsl;
+ private KeyManager[] keyManagers;
+
+ private OkHttpClient httpClient;
+ private JSON json;
+
+ private HttpLoggingInterceptor loggingInterceptor;
+
+ {{#dynamicOperations}}
+ private Map operationLookupMap = new HashMap<>();
+
+ {{/dynamicOperations}}
+ /**
+ * Basic constructor for ApiClient
+ */
+ public ApiClient() {
+ init();
+ initHttpClient();
+
+ // 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}}{{#isOAuth}}
+ authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}
+ // Prevent the authentications from being modified.
+ authentications = Collections.unmodifiableMap(authentications);
+ }
+
+ /**
+ * Basic constructor with custom OkHttpClient
+ *
+ * @param client a {@link okhttp3.OkHttpClient} object
+ */
+ public ApiClient(OkHttpClient client) {
+ init();
+
+ httpClient = client;
+
+ // 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}}{{#isOAuth}}
+ authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}
+ // Prevent the authentications from being modified.
+ authentications = Collections.unmodifiableMap(authentications);
+ }
+
+ {{#hasOAuthMethods}}
+ {{#oauthMethods}}
+ {{#-first}}
+ /**
+ * Constructor for ApiClient to support access token retry on 401/403 configured with client ID
+ *
+ * @param clientId client ID
+ */
+ public ApiClient(String clientId) {
+ this(clientId, null, null);
+ }
+
+ /**
+ * Constructor for ApiClient to support access token retry on 401/403 configured with client ID and additional parameters
+ *
+ * @param clientId client ID
+ * @param parameters a {@link java.util.Map} of parameters
+ */
+ public ApiClient(String clientId, Map parameters) {
+ this(clientId, null, parameters);
+ }
+
+ /**
+ * Constructor for ApiClient to support access token retry on 401/403 configured with client ID, secret, and additional parameters
+ *
+ * @param clientId client ID
+ * @param clientSecret client secret
+ * @param parameters a {@link java.util.Map} of parameters
+ */
+ public ApiClient(String clientId, String clientSecret, Map parameters) {
+ this(null, clientId, clientSecret, parameters);
+ }
+
+ /**
+ * Constructor for ApiClient to support access token retry on 401/403 configured with base path, client ID, secret, and additional parameters
+ *
+ * @param basePath base path
+ * @param clientId client ID
+ * @param clientSecret client secret
+ * @param parameters a {@link java.util.Map} of parameters
+ */
+ public ApiClient(String basePath, String clientId, String clientSecret, Map parameters) {
+ init();
+ if (basePath != null) {
+ this.basePath = basePath;
+ }
+
+{{#hasOAuthMethods}}
+ String tokenUrl = "{{tokenUrl}}";
+ if (!"".equals(tokenUrl) && !URI.create(tokenUrl).isAbsolute()) {
+ URI uri = URI.create(getBasePath());
+ tokenUrl = uri.getScheme() + ":" +
+ (uri.getAuthority() != null ? "//" + uri.getAuthority() : "") +
+ tokenUrl;
+ if (!URI.create(tokenUrl).isAbsolute()) {
+ throw new IllegalArgumentException("OAuth2 token URL must be an absolute URL");
+ }
+ }
+ RetryingOAuth retryingOAuth = new RetryingOAuth(tokenUrl, clientId, OAuthFlow.{{flow}}, clientSecret, parameters);
+ authentications.put(
+ "{{name}}",
+ retryingOAuth
+ );
+ initHttpClient(Collections.singletonList(retryingOAuth));
+{{/hasOAuthMethods}}
+ // 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}}
+
+ // Prevent the authentications from being modified.
+ authentications = Collections.unmodifiableMap(authentications);
+ }
+
+ {{/-first}}
+ {{/oauthMethods}}
+ {{/hasOAuthMethods}}
+ private void initHttpClient() {
+ initHttpClient(Collections.emptyList());
+ }
+
+ private void initHttpClient(List interceptors) {
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.addNetworkInterceptor(getProgressInterceptor());
+ for (Interceptor interceptor: interceptors) {
+ builder.addInterceptor(interceptor);
+ }
+ {{#useGzipFeature}}
+ // Enable gzip request compression
+ builder.addInterceptor(new GzipRequestInterceptor());
+ {{/useGzipFeature}}
+
+ httpClient = builder.build();
+ }
+
+ private void init() {
+ verifyingSsl = true;
+
+ json = new JSON();
+
+ // Set default User-Agent.
+ setUserAgent("{{{httpUserAgent}}}{{^httpUserAgent}}OpenAPI-Generator/{{{artifactVersion}}}/java{{/httpUserAgent}}");
+
+ authentications = new HashMap();
+ {{#dynamicOperations}}
+
+ OpenAPI openAPI = new OpenAPIV3Parser().read("openapi/openapi.yaml");
+ createOperationLookupMap(openAPI);
+ {{/dynamicOperations}}
+ }
+
+ /**
+ * Get base path
+ *
+ * @return Base path
+ */
+ public String getBasePath() {
+ return basePath;
+ }
+
+ /**
+ * Set base path
+ *
+ * @param basePath Base path of the URL (e.g {{{basePath}}}
+ * @return An instance of OkHttpClient
+ */
+ public ApiClient setBasePath(String basePath) {
+ this.basePath = basePath;
+ return this;
+ }
+
+ /**
+ * Get HTTP client
+ *
+ * @return An instance of OkHttpClient
+ */
+ public OkHttpClient getHttpClient() {
+ return httpClient;
+ }
+
+ /**
+ * Set HTTP client, which must never be null.
+ *
+ * @param newHttpClient An instance of OkHttpClient
+ * @return Api Client
+ * @throws java.lang.NullPointerException when newHttpClient is null
+ */
+ public ApiClient setHttpClient(OkHttpClient newHttpClient) {
+ this.httpClient = Objects.requireNonNull(newHttpClient, "HttpClient must not be null!");
+ return this;
+ }
+
+ /**
+ * Get JSON
+ *
+ * @return JSON object
+ */
+ public JSON getJSON() {
+ return json;
+ }
+
+ /**
+ * Set JSON
+ *
+ * @param json JSON object
+ * @return Api client
+ */
+ public ApiClient setJSON(JSON json) {
+ this.json = json;
+ return this;
+ }
+
+ /**
+ * True if isVerifyingSsl flag is on
+ *
+ * @return True if isVerifySsl flag is on
+ */
+ public boolean isVerifyingSsl() {
+ return verifyingSsl;
+ }
+
+ /**
+ * Configure whether to verify certificate and hostname when making https requests.
+ * Default to true.
+ * NOTE: Do NOT set to false in production code, otherwise you would face multiple types of cryptographic attacks.
+ *
+ * @param verifyingSsl True to verify TLS/SSL connection
+ * @return ApiClient
+ */
+ public ApiClient setVerifyingSsl(boolean verifyingSsl) {
+ this.verifyingSsl = verifyingSsl;
+ applySslSettings();
+ return this;
+ }
+
+ /**
+ * Get SSL CA cert.
+ *
+ * @return Input stream to the SSL CA cert
+ */
+ public InputStream getSslCaCert() {
+ return sslCaCert;
+ }
+
+ /**
+ * Configure the CA certificate to be trusted when making https requests.
+ * Use null to reset to default.
+ *
+ * @param sslCaCert input stream for SSL CA cert
+ * @return ApiClient
+ */
+ public ApiClient setSslCaCert(InputStream sslCaCert) {
+ this.sslCaCert = sslCaCert;
+ applySslSettings();
+ return this;
+ }
+
+ /**
+ * Getter for the field keyManagers
.
+ *
+ * @return an array of {@link javax.net.ssl.KeyManager} objects
+ */
+ public KeyManager[] getKeyManagers() {
+ return keyManagers;
+ }
+
+ /**
+ * Configure client keys to use for authorization in an SSL session.
+ * Use null to reset to default.
+ *
+ * @param managers The KeyManagers to use
+ * @return ApiClient
+ */
+ public ApiClient setKeyManagers(KeyManager[] managers) {
+ this.keyManagers = managers;
+ applySslSettings();
+ return this;
+ }
+
+ /**
+ * Getter for the field dateFormat
.
+ *
+ * @return a {@link java.text.DateFormat} object
+ */
+ public DateFormat getDateFormat() {
+ return dateFormat;
+ }
+
+ /**
+ * Setter for the field dateFormat
.
+ *
+ * @param dateFormat a {@link java.text.DateFormat} object
+ * @return a {@link org.openapitools.client.ApiClient} object
+ */
+ public ApiClient setDateFormat(DateFormat dateFormat) {
+ this.json.setDateFormat(dateFormat);
+ return this;
+ }
+
+ /**
+ * Set SqlDateFormat.
+ *
+ * @param dateFormat a {@link java.text.DateFormat} object
+ * @return a {@link org.openapitools.client.ApiClient} object
+ */
+ public ApiClient setSqlDateFormat(DateFormat dateFormat) {
+ this.json.setSqlDateFormat(dateFormat);
+ return this;
+ }
+
+ {{#joda}}
+ public ApiClient setDateTimeFormat(DateTimeFormatter dateFormat) {
+ this.json.setDateTimeFormat(dateFormat);
+ return this;
+ }
+
+ public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) {
+ this.json.setLocalDateFormat(dateFormat);
+ return this;
+ }
+
+ {{/joda}}
+ {{#jsr310}}
+ /**
+ * Set OffsetDateTimeFormat.
+ *
+ * @param dateFormat a {@link org.threeten.bp.format.DateTimeFormatter} object
+ * @return a {@link org.openapitools.client.ApiClient} object
+ */
+ public ApiClient setOffsetDateTimeFormat(DateTimeFormatter dateFormat) {
+ this.json.setOffsetDateTimeFormat(dateFormat);
+ return this;
+ }
+
+ /**
+ * Set LocalDateFormat.
+ *
+ * @param dateFormat a {@link org.threeten.bp.format.DateTimeFormatter} object
+ * @return a {@link org.openapitools.client.ApiClient} object
+ */
+ public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) {
+ this.json.setLocalDateFormat(dateFormat);
+ return this;
+ }
+
+ {{/jsr310}}
+ /**
+ * Set LenientOnJson.
+ *
+ * @param lenientOnJson a boolean
+ * @return a {@link org.openapitools.client.ApiClient} object
+ */
+ public ApiClient setLenientOnJson(boolean lenientOnJson) {
+ this.json.setLenientOnJson(lenientOnJson);
+ return this;
+ }
+
+ /**
+ * Get authentications (key: authentication name, value: authentication).
+ *
+ * @return Map of authentication objects
+ */
+ public Map getAuthentications() {
+ return authentications;
+ }
+
+ /**
+ * Get authentication for the given name.
+ *
+ * @param authName The authentication name
+ * @return The authentication, null if not found
+ */
+ public Authentication getAuthentication(String authName) {
+ return authentications.get(authName);
+ }
+
+ {{#hasHttpBearerMethods}}
+ /**
+ * Helper method to set access token for the first Bearer authentication.
+ * @param bearerToken Bearer token
+ */
+ public void setBearerToken(String bearerToken) {
+ for (Authentication auth : authentications.values()) {
+ if (auth instanceof HttpBearerAuth) {
+ ((HttpBearerAuth) auth).setBearerToken(bearerToken);
+ return;
+ }
+ }
+ throw new RuntimeException("No Bearer authentication configured!");
+ }
+ {{/hasHttpBearerMethods}}
+
+ /**
+ * Helper method to set username for the first HTTP basic authentication.
+ *
+ * @param username Username
+ */
+ public void setUsername(String username) {
+ for (Authentication auth : authentications.values()) {
+ if (auth instanceof HttpBasicAuth) {
+ ((HttpBasicAuth) auth).setUsername(username);
+ return;
+ }
+ }
+ throw new RuntimeException("No HTTP basic authentication configured!");
+ }
+
+ /**
+ * Helper method to set password for the first HTTP basic authentication.
+ *
+ * @param password Password
+ */
+ public void setPassword(String password) {
+ for (Authentication auth : authentications.values()) {
+ if (auth instanceof HttpBasicAuth) {
+ ((HttpBasicAuth) auth).setPassword(password);
+ return;
+ }
+ }
+ throw new RuntimeException("No HTTP basic authentication configured!");
+ }
+
+ /**
+ * Helper method to set API key value for the first API key authentication.
+ *
+ * @param apiKey API key
+ */
+ public void setApiKey(String apiKey) {
+ for (Authentication auth : authentications.values()) {
+ if (auth instanceof ApiKeyAuth) {
+ ((ApiKeyAuth) auth).setApiKey(apiKey);
+ return;
+ }
+ }
+ throw new RuntimeException("No API key authentication configured!");
+ }
+
+ /**
+ * Helper method to set API key prefix for the first API key authentication.
+ *
+ * @param apiKeyPrefix API key prefix
+ */
+ public void setApiKeyPrefix(String apiKeyPrefix) {
+ for (Authentication auth : authentications.values()) {
+ if (auth instanceof ApiKeyAuth) {
+ ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix);
+ return;
+ }
+ }
+ throw new RuntimeException("No API key authentication configured!");
+ }
+
+ /**
+ * Helper method to set access token for the first OAuth2 authentication.
+ *
+ * @param accessToken Access token
+ */
+ public void setAccessToken(String accessToken) {
+ {{#hasOAuthMethods}}
+ for (Authentication auth : authentications.values()) {
+ if (auth instanceof OAuth) {
+ ((OAuth) auth).setAccessToken(accessToken);
+ return;
+ }
+ }
+ {{/hasOAuthMethods}}
+ throw new RuntimeException("No OAuth2 authentication configured!");
+ }
+
+ /**
+ * Set the User-Agent header's value (by adding to the default header map).
+ *
+ * @param userAgent HTTP request's user agent
+ * @return ApiClient
+ */
+ public ApiClient setUserAgent(String userAgent) {
+ addDefaultHeader("User-Agent", userAgent);
+ return this;
+ }
+
+ /**
+ * Add a default header.
+ *
+ * @param key The header's key
+ * @param value The header's value
+ * @return ApiClient
+ */
+ public ApiClient addDefaultHeader(String key, String value) {
+ defaultHeaderMap.put(key, value);
+ return this;
+ }
+
+ /**
+ * Add a default cookie.
+ *
+ * @param key The cookie's key
+ * @param value The cookie's value
+ * @return ApiClient
+ */
+ public ApiClient addDefaultCookie(String key, String value) {
+ defaultCookieMap.put(key, value);
+ return this;
+ }
+
+ /**
+ * Check that whether debugging is enabled for this API client.
+ *
+ * @return True if debugging is enabled, false otherwise.
+ */
+ public boolean isDebugging() {
+ return debugging;
+ }
+
+ /**
+ * Enable/disable debugging for this API client.
+ *
+ * @param debugging To enable (true) or disable (false) debugging
+ * @return ApiClient
+ */
+ public ApiClient setDebugging(boolean debugging) {
+ if (debugging != this.debugging) {
+ if (debugging) {
+ loggingInterceptor = new HttpLoggingInterceptor();
+ loggingInterceptor.setLevel(Level.BODY);
+ httpClient = httpClient.newBuilder().addInterceptor(loggingInterceptor).build();
+ } else {
+ final OkHttpClient.Builder builder = httpClient.newBuilder();
+ builder.interceptors().remove(loggingInterceptor);
+ httpClient = builder.build();
+ loggingInterceptor = null;
+ }
+ }
+ this.debugging = debugging;
+ return this;
+ }
+
+ /**
+ * The path of temporary folder used to store downloaded files from endpoints
+ * with file response. The default value is null
, i.e. using
+ * the system's default temporary folder.
+ *
+ * @see createTempFile
+ * @return Temporary folder path
+ */
+ public String getTempFolderPath() {
+ return tempFolderPath;
+ }
+
+ /**
+ * Set the temporary folder path (for downloading files)
+ *
+ * @param tempFolderPath Temporary folder path
+ * @return ApiClient
+ */
+ public ApiClient setTempFolderPath(String tempFolderPath) {
+ this.tempFolderPath = tempFolderPath;
+ return this;
+ }
+
+ /**
+ * Get connection timeout (in milliseconds).
+ *
+ * @return Timeout in milliseconds
+ */
+ public int getConnectTimeout() {
+ return httpClient.connectTimeoutMillis();
+ }
+
+ /**
+ * Sets the connect timeout (in milliseconds).
+ * A value of 0 means no timeout, otherwise values must be between 1 and
+ * {@link java.lang.Integer#MAX_VALUE}.
+ *
+ * @param connectionTimeout connection timeout in milliseconds
+ * @return Api client
+ */
+ public ApiClient setConnectTimeout(int connectionTimeout) {
+ httpClient = httpClient.newBuilder().connectTimeout(connectionTimeout, TimeUnit.MILLISECONDS).build();
+ return this;
+ }
+
+ /**
+ * Get read timeout (in milliseconds).
+ *
+ * @return Timeout in milliseconds
+ */
+ public int getReadTimeout() {
+ return httpClient.readTimeoutMillis();
+ }
+
+ /**
+ * Sets the read timeout (in milliseconds).
+ * A value of 0 means no timeout, otherwise values must be between 1 and
+ * {@link java.lang.Integer#MAX_VALUE}.
+ *
+ * @param readTimeout read timeout in milliseconds
+ * @return Api client
+ */
+ public ApiClient setReadTimeout(int readTimeout) {
+ httpClient = httpClient.newBuilder().readTimeout(readTimeout, TimeUnit.MILLISECONDS).build();
+ return this;
+ }
+
+ /**
+ * Get write timeout (in milliseconds).
+ *
+ * @return Timeout in milliseconds
+ */
+ public int getWriteTimeout() {
+ return httpClient.writeTimeoutMillis();
+ }
+
+ /**
+ * Sets the write timeout (in milliseconds).
+ * A value of 0 means no timeout, otherwise values must be between 1 and
+ * {@link java.lang.Integer#MAX_VALUE}.
+ *
+ * @param writeTimeout connection timeout in milliseconds
+ * @return Api client
+ */
+ public ApiClient setWriteTimeout(int writeTimeout) {
+ httpClient = httpClient.newBuilder().writeTimeout(writeTimeout, TimeUnit.MILLISECONDS).build();
+ return this;
+ }
+
+ {{#hasOAuthMethods}}
+ /**
+ * Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one)
+ *
+ * @return Token request builder
+ */
+ public TokenRequestBuilder getTokenEndPoint() {
+ for (Authentication apiAuth : authentications.values()) {
+ if (apiAuth instanceof RetryingOAuth) {
+ RetryingOAuth retryingOAuth = (RetryingOAuth) apiAuth;
+ return retryingOAuth.getTokenRequestBuilder();
+ }
+ }
+ return null;
+ }
+ {{/hasOAuthMethods}}
+
+ /**
+ * Format the given parameter object into string.
+ *
+ * @param param Parameter
+ * @return String representation of the parameter
+ */
+ public String parameterToString(Object param) {
+ if (param == null) {
+ return "";
+ } else if (param instanceof Date {{#joda}}|| param instanceof DateTime || param instanceof LocalDate{{/joda}}{{#jsr310}}|| param instanceof OffsetDateTime || param instanceof LocalDate{{/jsr310}}) {
+ //Serialize to json string and remove the " enclosing characters
+ String jsonStr = json.serialize(param);
+ return jsonStr.substring(1, jsonStr.length() - 1);
+ } else if (param instanceof Collection) {
+ StringBuilder b = new StringBuilder();
+ for (Object o : (Collection) param) {
+ if (b.length() > 0) {
+ b.append(",");
+ }
+ b.append(String.valueOf(o));
+ }
+ return b.toString();
+ } else {
+ return String.valueOf(param);
+ }
+ }
+
+ /**
+ * Formats the specified query parameter to a list containing a single {@code Pair} object.
+ *
+ * Note that {@code value} must not be a collection.
+ *
+ * @param name The name of the parameter.
+ * @param value The value of the parameter.
+ * @return A list containing a single {@code Pair} object.
+ */
+ public List parameterToPair(String name, Object value) {
+ List params = new ArrayList();
+
+ // preconditions
+ if (name == null || name.isEmpty() || value == null || value instanceof Collection) {
+ return params;
+ }
+
+ params.add(new Pair(name, parameterToString(value)));
+ return params;
+ }
+
+ {{^dynamicOperations}}
+ /**
+ * Formats the specified collection query parameters to a list of {@code Pair} objects.
+ *
+ * Note that the values of each of the returned Pair objects are percent-encoded.
+ *
+ * @param collectionFormat The collection format of the parameter.
+ * @param name The name of the parameter.
+ * @param value The value of the parameter.
+ * @return A list of {@code Pair} objects.
+ */
+ public List parameterToPairs(String collectionFormat, String name, Collection value) {
+ List params = new ArrayList();
+
+ // preconditions
+ if (name == null || name.isEmpty() || value == null || value.isEmpty()) {
+ return params;
+ }
+
+ // create the params based on the collection format
+ if ("multi".equals(collectionFormat)) {
+ for (Object item : value) {
+ params.add(new Pair(name, escapeString(parameterToString(item))));
+ }
+ return params;
+ }
+
+ // collectionFormat is assumed to be "csv" by default
+ String delimiter = ",";
+
+ // escape all delimiters except commas, which are URI reserved
+ // characters
+ if ("ssv".equals(collectionFormat)) {
+ delimiter = escapeString(" ");
+ } else if ("tsv".equals(collectionFormat)) {
+ delimiter = escapeString("\t");
+ } else if ("pipes".equals(collectionFormat)) {
+ delimiter = escapeString("|");
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (Object item : value) {
+ sb.append(delimiter);
+ sb.append(escapeString(parameterToString(item)));
+ }
+
+ params.add(new Pair(name, sb.substring(delimiter.length())));
+
+ return params;
+ }
+ {{/dynamicOperations}}
+ {{#dynamicOperations}}
+ public List parameterToPairs(Parameter param, Collection value) {
+ List params = new ArrayList();
+
+ // preconditions
+ if (param == null || param.getName() == null || param.getName().isEmpty() || value == null) {
+ return params;
+ }
+
+ // create the params based on the collection format
+ if (StyleEnum.FORM.equals(param.getStyle()) && Boolean.TRUE.equals(param.getExplode())) {
+ for (Object item : value) {
+ params.add(new Pair(param.getName(), escapeString(parameterToString(item))));
+ }
+ return params;
+ }
+
+ // collectionFormat is assumed to be "csv" by default
+ String delimiter = ",";
+
+ // escape all delimiters except commas, which are URI reserved
+ // characters
+ if (StyleEnum.SPACEDELIMITED.equals(param.getStyle())) {
+ delimiter = escapeString(" ");
+ } else if (StyleEnum.PIPEDELIMITED.equals(param.getStyle())) {
+ delimiter = escapeString("|");
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (Object item : value) {
+ sb.append(delimiter);
+ sb.append(escapeString(parameterToString(item)));
+ }
+
+ params.add(new Pair(param.getName(), sb.substring(delimiter.length())));
+
+ return params;
+ }
+ {{/dynamicOperations}}
+
+ /**
+ * Formats the specified collection path parameter to a string value.
+ *
+ * @param collectionFormat The collection format of the parameter.
+ * @param value The value of the parameter.
+ * @return String representation of the parameter
+ */
+ public String collectionPathParameterToString(String collectionFormat, Collection value) {
+ // create the value based on the collection format
+ if ("multi".equals(collectionFormat)) {
+ // not valid for path params
+ return parameterToString(value);
+ }
+
+ // collectionFormat is assumed to be "csv" by default
+ String delimiter = ",";
+
+ if ("ssv".equals(collectionFormat)) {
+ delimiter = " ";
+ } else if ("tsv".equals(collectionFormat)) {
+ delimiter = "\t";
+ } else if ("pipes".equals(collectionFormat)) {
+ delimiter = "|";
+ }
+
+ StringBuilder sb = new StringBuilder() ;
+ for (Object item : value) {
+ sb.append(delimiter);
+ sb.append(parameterToString(item));
+ }
+
+ return sb.substring(delimiter.length());
+ }
+
+ /**
+ * Sanitize filename by removing path.
+ * e.g. ../../sun.gif becomes sun.gif
+ *
+ * @param filename The filename to be sanitized
+ * @return The sanitized filename
+ */
+ public String sanitizeFilename(String filename) {
+ return filename.replaceAll(".*[/\\\\]", "");
+ }
+
+ /**
+ * Check if the given MIME is a JSON MIME.
+ * JSON MIME examples:
+ * application/json
+ * application/json; charset=UTF8
+ * APPLICATION/JSON
+ * application/vnd.company+json
+ * "* / *" is also default to JSON
+ * @param mime MIME (Multipurpose Internet Mail Extensions)
+ * @return True if the given MIME is JSON, false otherwise.
+ */
+ public boolean isJsonMime(String mime) {
+ String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$";
+ return mime != null && (mime.matches(jsonMime) || mime.equals("*/*"));
+ }
+
+ /**
+ * Select the Accept header's value from the given accepts array:
+ * if JSON exists in the given array, use it;
+ * otherwise use all of them (joining into a string)
+ *
+ * @param accepts The accepts array to select from
+ * @return The Accept header to use. If the given array is empty,
+ * null will be returned (not to set the Accept header explicitly).
+ */
+ public String selectHeaderAccept(String[] accepts) {
+ if (accepts.length == 0) {
+ return null;
+ }
+ for (String accept : accepts) {
+ if (isJsonMime(accept)) {
+ return accept;
+ }
+ }
+ return StringUtil.join(accepts, ",");
+ }
+
+ /**
+ * Select the Content-Type header's value from the given array:
+ * if JSON exists in the given array, use it;
+ * otherwise use the first one of the array.
+ *
+ * @param contentTypes The Content-Type array to select from
+ * @return The Content-Type header to use. If the given array is empty,
+ * returns null. If it matches "any", JSON will be used.
+ */
+ public String selectHeaderContentType(String[] contentTypes) {
+ if (contentTypes.length == 0) {
+ return null;
+ }
+
+ if (contentTypes[0].equals("*/*")) {
+ return "application/json";
+ }
+
+ for (String contentType : contentTypes) {
+ if (isJsonMime(contentType)) {
+ return contentType;
+ }
+ }
+
+ return contentTypes[0];
+ }
+
+ /**
+ * Escape the given string to be used as URL query value.
+ *
+ * @param str String to be escaped
+ * @return Escaped string
+ */
+ public String escapeString(String str) {
+ try {
+ return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20");
+ } catch (UnsupportedEncodingException e) {
+ return str;
+ }
+ }
+
+ /**
+ * Deserialize response body to Java object, according to the return type and
+ * the Content-Type response header.
+ *
+ * @param Type
+ * @param response HTTP response
+ * @param returnType The type of the Java object
+ * @return The deserialized Java object
+ * @throws org.openapitools.client.ApiException If fail to deserialize response body, i.e. cannot read response body
+ * or the Content-Type of the response is not supported.
+ */
+ @SuppressWarnings("unchecked")
+ public T deserialize(Response response, Type returnType) throws ApiException {
+ if (response == null || returnType == null) {
+ return null;
+ }
+
+ if ("byte[]".equals(returnType.toString())) {
+ // Handle binary response (byte array).
+ try {
+ return (T) response.body().bytes();
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ } else if (returnType.equals(File.class)) {
+ // Handle file downloading.
+ return (T) downloadFileFromResponse(response);
+ }
+
+ String respBody;
+ try {
+ if (response.body() != null)
+ respBody = response.body().string();
+ else
+ respBody = null;
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+
+ if (respBody == null || "".equals(respBody)) {
+ return null;
+ }
+
+ String contentType = response.headers().get("Content-Type");
+ if (contentType == null) {
+ // ensuring a default content type
+ contentType = "application/json";
+ }
+ if (isJsonMime(contentType)) {
+ return json.deserialize(respBody, returnType);
+ } else if (returnType.equals(String.class)) {
+ // Expecting string, return the raw response body.
+ return (T) respBody;
+ } else {
+ throw new ApiException(
+ "Content type \"" + contentType + "\" is not supported for type: " + returnType,
+ response.code(),
+ response.headers().toMultimap(),
+ respBody);
+ }
+ }
+
+ /**
+ * Serialize the given Java object into request body according to the object's
+ * class and the request Content-Type.
+ *
+ * @param obj The Java object
+ * @param contentType The request Content-Type
+ * @return The serialized request body
+ * @throws org.openapitools.client.ApiException If fail to serialize the given object
+ */
+ public RequestBody serialize(Object obj, String contentType) throws ApiException {
+ if (obj instanceof byte[]) {
+ // Binary (byte array) body parameter support.
+ return RequestBody.create((byte[]) obj, MediaType.parse(contentType));
+ } else if (obj instanceof File) {
+ // File body parameter support.
+ return RequestBody.create((File) obj, MediaType.parse(contentType));
+ } else if (isJsonMime(contentType)) {
+ String content;
+ if (obj != null) {
+ content = json.serialize(obj);
+ } else {
+ content = null;
+ }
+ return RequestBody.create(content, MediaType.parse(contentType));
+ } else {
+ throw new ApiException("Content type \"" + contentType + "\" is not supported");
+ }
+ }
+
+ /**
+ * Download file from the given response.
+ *
+ * @param response An instance of the Response object
+ * @throws org.openapitools.client.ApiException If fail to read file content from response and write to disk
+ * @return Downloaded file
+ */
+ public File downloadFileFromResponse(Response response) throws ApiException {
+ try {
+ File file = prepareDownloadFile(response);
+ BufferedSink sink = Okio.buffer(Okio.sink(file));
+ sink.writeAll(response.body().source());
+ sink.close();
+ return file;
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ }
+
+ /**
+ * Prepare file for download
+ *
+ * @param response An instance of the Response object
+ * @return Prepared file for the download
+ * @throws java.io.IOException If fail to prepare file for download
+ */
+ public File prepareDownloadFile(Response response) throws IOException {
+ String filename = null;
+ String contentDisposition = response.header("Content-Disposition");
+ if (contentDisposition != null && !"".equals(contentDisposition)) {
+ // Get filename from the Content-Disposition header.
+ Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?");
+ Matcher matcher = pattern.matcher(contentDisposition);
+ if (matcher.find()) {
+ filename = sanitizeFilename(matcher.group(1));
+ }
+ }
+
+ String prefix = null;
+ String suffix = null;
+ if (filename == null) {
+ prefix = "download-";
+ suffix = "";
+ } else {
+ int pos = filename.lastIndexOf(".");
+ if (pos == -1) {
+ prefix = filename + "-";
+ } else {
+ prefix = filename.substring(0, pos) + "-";
+ suffix = filename.substring(pos);
+ }
+ // Files.createTempFile requires the prefix to be at least three characters long
+ if (prefix.length() < 3)
+ prefix = "download-";
+ }
+
+ if (tempFolderPath == null)
+ return Files.createTempFile(prefix, suffix).toFile();
+ else
+ return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile();
+ }
+
+ /**
+ * {@link #execute(Call, Type)}
+ *
+ * @param Type
+ * @param call An instance of the Call object
+ * @return ApiResponse<T>
+ * @throws org.openapitools.client.ApiException If fail to execute the call
+ */
+ public ApiResponse execute(Call call) throws ApiException {
+ return execute(call, null);
+ }
+
+ /**
+ * Execute HTTP call and deserialize the HTTP response body into the given return type.
+ *
+ * @param returnType The return type used to deserialize HTTP response body
+ * @param The return type corresponding to (same with) returnType
+ * @param call Call
+ * @return ApiResponse object containing response status, headers and
+ * data, which is a Java object deserialized from response body and would be null
+ * when returnType is null.
+ * @throws org.openapitools.client.ApiException If fail to execute the call
+ */
+ public ApiResponse execute(Call call, Type returnType) throws ApiException {
+ try {
+ Response response = call.execute();
+ T data = handleResponse(response, returnType);
+ return new ApiResponse(response.code(), response.headers().toMultimap(), data);
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ }
+
+ {{#supportStreaming}}
+ /**
+ * Execute stream.
+ *
+ * @param call a {@link okhttp3.Call} object
+ * @param returnType a {@link java.lang.reflect.Type} object
+ * @return a {@link java.io.InputStream} object
+ * @throws org.openapitools.client.ApiException if any.
+ */
+ public InputStream executeStream(Call call, Type returnType) throws ApiException {
+ try {
+ Response response = call.execute();
+ if (!response.isSuccessful()) {
+ throw new ApiException(response.code(), response.message());
+ }
+ if (response.body() == null) {
+ return null;
+ }
+ return response.body().byteStream();
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ }
+
+ {{/supportStreaming}}
+ /**
+ * {@link #executeAsync(Call, Type, ApiCallback)}
+ *
+ * @param Type
+ * @param call An instance of the Call object
+ * @param callback ApiCallback<T>
+ */
+ public void executeAsync(Call call, ApiCallback callback) {
+ executeAsync(call, null, callback);
+ }
+
+ /**
+ * Execute HTTP call asynchronously.
+ *
+ * @param Type
+ * @param call The callback to be executed when the API call finishes
+ * @param returnType Return type
+ * @param callback ApiCallback
+ * @see #execute(Call, Type)
+ */
+ @SuppressWarnings("unchecked")
+ public void executeAsync(Call call, final Type returnType, final ApiCallback callback) {
+ call.enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ callback.onFailure(new ApiException(e), 0, null);
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ T result;
+ try {
+ result = (T) handleResponse(response, returnType);
+ } catch (ApiException e) {
+ callback.onFailure(e, response.code(), response.headers().toMultimap());
+ return;
+ } catch (Exception e) {
+ callback.onFailure(new ApiException(e), response.code(), response.headers().toMultimap());
+ return;
+ }
+ callback.onSuccess(result, response.code(), response.headers().toMultimap());
+ }
+ });
+ }
+
+ /**
+ * Handle the given response, return the deserialized object when the response is successful.
+ *
+ * @param Type
+ * @param response Response
+ * @param returnType Return type
+ * @return Type
+ * @throws org.openapitools.client.ApiException If the response has an unsuccessful status code or
+ * fail to deserialize the response body
+ */
+ public T handleResponse(Response response, Type returnType) throws ApiException {
+ if (response.isSuccessful()) {
+ if (returnType == null || response.code() == 204) {
+ // returning null if the returnType is not defined,
+ // or the status code is 204 (No Content)
+ if (response.body() != null) {
+ try {
+ response.body().close();
+ } catch (Exception e) {
+ throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap());
+ }
+ }
+ return null;
+ } else {
+ return deserialize(response, returnType);
+ }
+ } else {
+ String respBody = null;
+ if (response.body() != null) {
+ try {
+ respBody = response.body().string();
+ } catch (IOException e) {
+ throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap());
+ }
+ }
+ throw new ApiException(response.message(), response.code(), response.headers().toMultimap(), respBody);
+ }
+ }
+
+ /**
+ * Build HTTP call with the given options.
+ *
+ * @param path The sub-path of the HTTP URL
+ * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE"
+ * @param queryParams The query parameters
+ * @param collectionQueryParams The collection query parameters
+ * @param body The request body object
+ * @param headerParams The header parameters
+ * @param cookieParams The cookie parameters
+ * @param formParams The form parameters
+ * @param authNames The authentications to apply
+ * @param callback Callback for upload/download progress
+ * @return The HTTP call
+ * @throws org.openapitools.client.ApiException If fail to serialize the request body object
+ */
+ public Call buildCall(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String[] authNames, ApiCallback callback) throws ApiException {
+ Request request = buildRequest(path, method, queryParams, collectionQueryParams, body, headerParams, cookieParams, formParams, authNames, callback);
+
+ return httpClient.newCall(request);
+ }
+
+ /**
+ * Build an HTTP request with the given options.
+ *
+ * @param path The sub-path of the HTTP URL
+ * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE"
+ * @param queryParams The query parameters
+ * @param collectionQueryParams The collection query parameters
+ * @param body The request body object
+ * @param headerParams The header parameters
+ * @param cookieParams The cookie parameters
+ * @param formParams The form parameters
+ * @param authNames The authentications to apply
+ * @param callback Callback for upload/download progress
+ * @return The HTTP request
+ * @throws org.openapitools.client.ApiException If fail to serialize the request body object
+ */
+ public Request buildRequest(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String[] authNames, ApiCallback callback) throws ApiException {
+ // aggregate queryParams (non-collection) and collectionQueryParams into allQueryParams
+ List allQueryParams = new ArrayList(queryParams);
+ allQueryParams.addAll(collectionQueryParams);
+
+ final String url = buildUrl(path, queryParams, collectionQueryParams);
+
+ // prepare HTTP request body
+ RequestBody reqBody;
+ String contentType = headerParams.get("Content-Type");
+
+ if (!HttpMethod.permitsRequestBody(method)) {
+ reqBody = null;
+ } else if ("application/x-www-form-urlencoded".equals(contentType)) {
+ reqBody = buildRequestBodyFormEncoding(formParams);
+ } else if ("multipart/form-data".equals(contentType)) {
+ reqBody = buildRequestBodyMultipart(formParams);
+ } else if (body == null) {
+ if ("DELETE".equals(method)) {
+ // allow calling DELETE without sending a request body
+ reqBody = null;
+ } else {
+ // use an empty request body (for POST, PUT and PATCH)
+ reqBody = RequestBody.create("", MediaType.parse(contentType));
+ }
+ } else {
+ reqBody = serialize(body, contentType);
+ }
+
+ // update parameters with authentication settings
+ updateParamsForAuth(authNames, allQueryParams, headerParams, cookieParams, requestBodyToString(reqBody), method, URI.create(url));
+
+ final Request.Builder reqBuilder = new Request.Builder().url(url);
+ processHeaderParams(headerParams, reqBuilder);
+ processCookieParams(cookieParams, reqBuilder);
+
+ // Associate callback with request (if not null) so interceptor can
+ // access it when creating ProgressResponseBody
+ reqBuilder.tag(callback);
+
+ Request request = null;
+
+ if (callback != null && reqBody != null) {
+ ProgressRequestBody progressRequestBody = new ProgressRequestBody(reqBody, callback);
+ request = reqBuilder.method(method, progressRequestBody).build();
+ } else {
+ request = reqBuilder.method(method, reqBody).build();
+ }
+
+ return request;
+ }
+
+ /**
+ * Build full URL by concatenating base path, the given sub path and query parameters.
+ *
+ * @param path The sub path
+ * @param queryParams The query parameters
+ * @param collectionQueryParams The collection query parameters
+ * @return The full URL
+ */
+ public String buildUrl(String path, List queryParams, List collectionQueryParams) {
+ final StringBuilder url = new StringBuilder();
+ url.append(basePath).append(path);
+
+ if (queryParams != null && !queryParams.isEmpty()) {
+ // support (constant) query string in `path`, e.g. "/posts?draft=1"
+ String prefix = path.contains("?") ? "&" : "?";
+ for (Pair param : queryParams) {
+ if (param.getValue() != null) {
+ if (prefix != null) {
+ url.append(prefix);
+ prefix = null;
+ } else {
+ url.append("&");
+ }
+ String value = parameterToString(param.getValue());
+ url.append(escapeString(param.getName())).append("=").append(escapeString(value));
+ }
+ }
+ }
+
+ if (collectionQueryParams != null && !collectionQueryParams.isEmpty()) {
+ String prefix = url.toString().contains("?") ? "&" : "?";
+ for (Pair param : collectionQueryParams) {
+ if (param.getValue() != null) {
+ if (prefix != null) {
+ url.append(prefix);
+ prefix = null;
+ } else {
+ url.append("&");
+ }
+ String value = parameterToString(param.getValue());
+ // collection query parameter value already escaped as part of parameterToPairs
+ url.append(escapeString(param.getName())).append("=").append(value);
+ }
+ }
+ }
+
+ return url.toString();
+ }
+
+ /**
+ * Set header parameters to the request builder, including default headers.
+ *
+ * @param headerParams Header parameters in the form of Map
+ * @param reqBuilder Request.Builder
+ */
+ public void processHeaderParams(Map headerParams, Request.Builder reqBuilder) {
+ for (Entry param : headerParams.entrySet()) {
+ reqBuilder.header(param.getKey(), parameterToString(param.getValue()));
+ }
+ for (Entry header : defaultHeaderMap.entrySet()) {
+ if (!headerParams.containsKey(header.getKey())) {
+ reqBuilder.header(header.getKey(), parameterToString(header.getValue()));
+ }
+ }
+ }
+
+ /**
+ * Set cookie parameters to the request builder, including default cookies.
+ *
+ * @param cookieParams Cookie parameters in the form of Map
+ * @param reqBuilder Request.Builder
+ */
+ public void processCookieParams(Map cookieParams, Request.Builder reqBuilder) {
+ for (Entry param : cookieParams.entrySet()) {
+ reqBuilder.addHeader("Cookie", String.format("%s=%s", param.getKey(), param.getValue()));
+ }
+ for (Entry param : defaultCookieMap.entrySet()) {
+ if (!cookieParams.containsKey(param.getKey())) {
+ reqBuilder.addHeader("Cookie", String.format("%s=%s", param.getKey(), param.getValue()));
+ }
+ }
+ }
+
+ /**
+ * Update query and header parameters based on authentication settings.
+ *
+ * @param authNames The authentications to apply
+ * @param queryParams List of query parameters
+ * @param headerParams Map of header parameters
+ * @param cookieParams Map of cookie parameters
+ * @param payload HTTP request body
+ * @param method HTTP method
+ * @param uri URI
+ */
+ public void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams,
+ Map cookieParams, String payload, String method, URI uri) throws ApiException {
+ for (String authName : authNames) {
+ Authentication auth = authentications.get(authName);
+ if (auth == null) {
+ throw new RuntimeException("Authentication undefined: " + authName);
+ }
+ auth.applyToParams(queryParams, headerParams, cookieParams, payload, method, uri);
+ }
+ }
+
+ /**
+ * Build a form-encoding request body with the given form parameters.
+ *
+ * @param formParams Form parameters in the form of Map
+ * @return RequestBody
+ */
+ public RequestBody buildRequestBodyFormEncoding(Map formParams) {
+ okhttp3.FormBody.Builder formBuilder = new okhttp3.FormBody.Builder();
+ for (Entry param : formParams.entrySet()) {
+ formBuilder.add(param.getKey(), parameterToString(param.getValue()));
+ }
+ return formBuilder.build();
+ }
+
+ /**
+ * Build a multipart (file uploading) request body with the given form parameters,
+ * which could contain text fields and file fields.
+ *
+ * @param formParams Form parameters in the form of Map
+ * @return RequestBody
+ */
+ public RequestBody buildRequestBodyMultipart(Map formParams) {
+ MultipartBody.Builder mpBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
+ for (Entry param : formParams.entrySet()) {
+ if (param.getValue() instanceof File) {
+ File file = (File) param.getValue();
+ Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + param.getKey() + "\"; filename=\"" + file.getName() + "\"");
+ MediaType mediaType = MediaType.parse(guessContentTypeFromFile(file));
+ mpBuilder.addPart(partHeaders, RequestBody.create(file, mediaType));
+ } else {
+ Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + param.getKey() + "\"");
+ mpBuilder.addPart(partHeaders, RequestBody.create(parameterToString(param.getValue()), null));
+ }
+ }
+ return mpBuilder.build();
+ }
+
+ /**
+ * Guess Content-Type header from the given file (defaults to "application/octet-stream").
+ *
+ * @param file The given file
+ * @return The guessed Content-Type
+ */
+ public String guessContentTypeFromFile(File file) {
+ String contentType = URLConnection.guessContentTypeFromName(file.getName());
+ if (contentType == null) {
+ return "application/octet-stream";
+ } else {
+ return contentType;
+ }
+ }
+
+ /**
+ * Get network interceptor to add it to the httpClient to track download progress for
+ * async requests.
+ */
+ private Interceptor getProgressInterceptor() {
+ return new Interceptor() {
+ @Override
+ public Response intercept(Interceptor.Chain chain) throws IOException {
+ final Request request = chain.request();
+ final Response originalResponse = chain.proceed(request);
+ if (request.tag() instanceof ApiCallback) {
+ final ApiCallback callback = (ApiCallback) request.tag();
+ return originalResponse.newBuilder()
+ .body(new ProgressResponseBody(originalResponse.body(), callback))
+ .build();
+ }
+ return originalResponse;
+ }
+ };
+ }
+
+ /**
+ * Apply SSL related settings to httpClient according to the current values of
+ * verifyingSsl and sslCaCert.
+ */
+ private void applySslSettings() {
+ try {
+ TrustManager[] trustManagers;
+ HostnameVerifier hostnameVerifier;
+ if (!verifyingSsl) {
+ trustManagers = new TrustManager[]{
+ new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return new java.security.cert.X509Certificate[]{};
+ }
+ }
+ };
+ hostnameVerifier = new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ };
+ } else {
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+
+ if (sslCaCert == null) {
+ trustManagerFactory.init((KeyStore) null);
+ } else {
+ char[] password = null; // Any password will work.
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ Collection extends Certificate> certificates = certificateFactory.generateCertificates(sslCaCert);
+ if (certificates.isEmpty()) {
+ throw new IllegalArgumentException("expected non-empty set of trusted certificates");
+ }
+ KeyStore caKeyStore = newEmptyKeyStore(password);
+ int index = 0;
+ for (Certificate certificate : certificates) {
+ String certificateAlias = "ca" + Integer.toString(index++);
+ caKeyStore.setCertificateEntry(certificateAlias, certificate);
+ }
+ trustManagerFactory.init(caKeyStore);
+ }
+ trustManagers = trustManagerFactory.getTrustManagers();
+ hostnameVerifier = OkHostnameVerifier.INSTANCE;
+ }
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(keyManagers, trustManagers, new SecureRandom());
+ httpClient = httpClient.newBuilder()
+ .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0])
+ .hostnameVerifier(hostnameVerifier)
+ .build();
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
+ try {
+ KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keyStore.load(null, password);
+ return keyStore;
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+ {{#dynamicOperations}}
+
+ public ApiClient createOperationLookupMap(OpenAPI openAPI) {
+ operationLookupMap = new HashMap<>();
+ for (Map.Entry pathItemEntry : openAPI.getPaths().entrySet()) {
+ String path = pathItemEntry.getKey();
+ PathItem pathItem = pathItemEntry.getValue();
+ addOperationLookupEntry(path, "GET", pathItem.getGet());
+ addOperationLookupEntry(path, "PUT", pathItem.getPut());
+ addOperationLookupEntry(path, "POST", pathItem.getPost());
+ addOperationLookupEntry(path, "DELETE", pathItem.getDelete());
+ addOperationLookupEntry(path, "OPTIONS", pathItem.getOptions());
+ addOperationLookupEntry(path, "HEAD", pathItem.getHead());
+ addOperationLookupEntry(path, "PATCH", pathItem.getPatch());
+ addOperationLookupEntry(path, "TRACE", pathItem.getTrace());
+ }
+ return this;
+ }
+
+ private void addOperationLookupEntry(String path, String method, Operation operation) {
+ if ( operation != null && operation.getOperationId() != null) {
+ operationLookupMap.put(
+ operation.getOperationId(),
+ new ApiOperation(path, method, operation));
+ }
+ }
+
+ public Map getOperationLookupMap() {
+ return operationLookupMap;
+ }
+
+ public String fillParametersFromOperation(
+ Operation operation,
+ Map paramMap,
+ String path,
+ List queryParams,
+ List collectionQueryParams,
+ Map headerParams,
+ Map cookieParams
+ ) {
+ for (Map.Entry entry : paramMap.entrySet()) {
+ Object value = entry.getValue();
+ for (Parameter param : operation.getParameters()) {
+ if (entry.getKey().equals(param.getName())) {
+ switch (param.getIn()) {
+ case "path":
+ path = path.replaceAll("\\{" + param.getName() + "\\}", escapeString(value.toString()));
+ break;
+ case "query":
+ if (value instanceof Collection>) {
+ collectionQueryParams.addAll(parameterToPairs(param, (Collection) value));
+ } else {
+ queryParams.addAll(parameterToPair(param.getName(), value));
+ }
+ break;
+ case "header":
+ headerParams.put(param.getName(), parameterToString(value));
+ break;
+ case "cookie":
+ cookieParams.put(param.getName(), parameterToString(value));
+ break;
+ default:
+ throw new IllegalStateException("Unexpected param in: " + param.getIn());
+ }
+
+ }
+ }
+ }
+ return path;
+ }
+ {{/dynamicOperations}}
+
+ /**
+ * Convert the HTTP request body to a string.
+ *
+ * @param request The HTTP request object
+ * @return The string representation of the HTTP request body
+ * @throws org.openapitools.client.ApiException If fail to serialize the request body object into a string
+ */
+ private String requestBodyToString(RequestBody requestBody) throws ApiException {
+ if (requestBody != null) {
+ try {
+ final Buffer buffer = new Buffer();
+ requestBody.writeTo(buffer);
+ return buffer.readUtf8();
+ } catch (final IOException e) {
+ throw new ApiException(e);
+ }
+ }
+
+ // empty http request body
+ return "";
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiResponse.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiResponse.mustache
new file mode 100644
index 00000000000..cecbaac1df2
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ApiResponse.mustache
@@ -0,0 +1,75 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+import java.util.List;
+import java.util.Map;
+{{#caseInsensitiveResponseHeaders}}
+import java.util.Map.Entry;
+import java.util.TreeMap;
+{{/caseInsensitiveResponseHeaders}}
+
+/**
+ * API response returned by API call.
+ */
+public class ApiResponse {
+ final private int statusCode;
+ final private Map> headers;
+ final private T data;
+
+ /**
+ * Constructor for ApiResponse.
+ *
+ * @param statusCode The status code of HTTP response
+ * @param headers The headers of HTTP response
+ */
+ public ApiResponse(int statusCode, Map> headers) {
+ this(statusCode, headers, null);
+ }
+
+ /**
+ * Constructor for ApiResponse.
+ *
+ * @param statusCode The status code of HTTP response
+ * @param headers The headers of HTTP response
+ * @param data The object deserialized from response bod
+ */
+ public ApiResponse(int statusCode, Map> headers, T data) {
+ this.statusCode = statusCode;
+ {{#caseInsensitiveResponseHeaders}}
+ Map> responseHeaders = new TreeMap>(String.CASE_INSENSITIVE_ORDER);
+ for(Entry> entry : headers.entrySet()){
+ responseHeaders.put(entry.getKey().toLowerCase(), entry.getValue());
+ }
+ {{/caseInsensitiveResponseHeaders}}
+ this.headers = {{#caseInsensitiveResponseHeaders}}responseHeaders{{/caseInsensitiveResponseHeaders}}{{^caseInsensitiveResponseHeaders}}headers{{/caseInsensitiveResponseHeaders}};
+ this.data = data;
+ }
+
+ /**
+ * Get the status code
.
+ *
+ * @return the status code
+ */
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ /**
+ * Get the headers
.
+ *
+ * @return a {@link java.util.Map} of headers
+ */
+ public Map> getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Get the data
.
+ *
+ * @return the data
+ */
+ public T getData() {
+ return data;
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/GzipRequestInterceptor.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/GzipRequestInterceptor.mustache
new file mode 100644
index 00000000000..b633aa8f586
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/GzipRequestInterceptor.mustache
@@ -0,0 +1,74 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+import okhttp3.*;
+import okio.Buffer;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
+
+import java.io.IOException;
+
+/**
+ * Encodes request bodies using gzip.
+ *
+ * Taken from https://github.com/square/okhttp/issues/350
+ */
+class GzipRequestInterceptor implements Interceptor {
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Request originalRequest = chain.request();
+ if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
+ return chain.proceed(originalRequest);
+ }
+
+ Request compressedRequest = originalRequest.newBuilder()
+ .header("Content-Encoding", "gzip")
+ .method(originalRequest.method(), forceContentLength(gzip(originalRequest.body())))
+ .build();
+ return chain.proceed(compressedRequest);
+ }
+
+ private RequestBody forceContentLength(final RequestBody requestBody) throws IOException {
+ final Buffer buffer = new Buffer();
+ requestBody.writeTo(buffer);
+ return new RequestBody() {
+ @Override
+ public MediaType contentType() {
+ return requestBody.contentType();
+ }
+
+ @Override
+ public long contentLength() {
+ return buffer.size();
+ }
+
+ @Override
+ public void writeTo(BufferedSink sink) throws IOException {
+ sink.write(buffer.snapshot());
+ }
+ };
+ }
+
+ private RequestBody gzip(final RequestBody body) {
+ return new RequestBody() {
+ @Override
+ public MediaType contentType() {
+ return body.contentType();
+ }
+
+ @Override
+ public long contentLength() {
+ return -1; // We don't know the compressed length in advance!
+ }
+
+ @Override
+ public void writeTo(BufferedSink sink) throws IOException {
+ BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
+ body.writeTo(gzipSink);
+ gzipSink.close();
+ }
+ };
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/JSON.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/JSON.mustache
new file mode 100644
index 00000000000..56477b8dc17
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/JSON.mustache
@@ -0,0 +1,541 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonParseException;
+import com.google.gson.TypeAdapter;
+import com.google.gson.internal.bind.util.ISO8601Utils;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import com.google.gson.JsonElement;
+import io.gsonfire.GsonFireBuilder;
+import io.gsonfire.TypeSelector;
+{{#joda}}
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.DateTimeFormatterBuilder;
+import org.joda.time.format.ISODateTimeFormat;
+{{/joda}}
+{{#threetenbp}}
+import org.threeten.bp.LocalDate;
+import org.threeten.bp.OffsetDateTime;
+import org.threeten.bp.format.DateTimeFormatter;
+{{/threetenbp}}
+
+import okio.ByteString;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Type;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.ParsePosition;
+{{#java8}}
+import java.time.LocalDate;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+{{/java8}}
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
+
+/*
+ * A JSON utility class
+ *
+ * NOTE: in the future, this class may be converted to static, which may break
+ * backward-compatibility
+ */
+public class JSON {
+ private Gson gson;
+ private boolean isLenientOnJson = false;
+ private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter();
+ private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter();
+ {{#joda}}
+ private DateTimeTypeAdapter dateTimeTypeAdapter = new DateTimeTypeAdapter();
+ private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter();
+ {{/joda}}
+ {{#jsr310}}
+ private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter();
+ private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter();
+ {{/jsr310}}
+ private ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter();
+
+ @SuppressWarnings("unchecked")
+ public static GsonBuilder createGson() {
+ GsonFireBuilder fireBuilder = new GsonFireBuilder()
+ {{#models}}
+ {{#model}}
+ {{#discriminator}}
+ .registerTypeSelector({{modelPackage}}.{{classname}}.class, new TypeSelector<{{modelPackage}}.{{classname}}>() {
+ @Override
+ public Class extends {{modelPackage}}.{{classname}}> getClassForElement(JsonElement readElement) {
+ Map classByDiscriminatorValue = new HashMap();
+ {{#mappedModels}}
+ classByDiscriminatorValue.put("{{mappingName}}"{{^discriminatorCaseSensitive}}.toUpperCase(Locale.ROOT){{/discriminatorCaseSensitive}}, {{modelPackage}}.{{modelName}}.class);
+ {{/mappedModels}}
+ classByDiscriminatorValue.put("{{name}}"{{^discriminatorCaseSensitive}}.toUpperCase(Locale.ROOT){{/discriminatorCaseSensitive}}, {{modelPackage}}.{{classname}}.class);
+ return getClassByDiscriminator(classByDiscriminatorValue,
+ getDiscriminatorValue(readElement, "{{{propertyBaseName}}}"));
+ }
+ })
+ {{/discriminator}}
+ {{/model}}
+ {{/models}}
+ ;
+ GsonBuilder builder = fireBuilder.createGsonBuilder();
+ {{#disableHtmlEscaping}}
+ builder.disableHtmlEscaping();
+ {{/disableHtmlEscaping}}
+ return builder;
+ }
+
+ private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) {
+ JsonElement element = readElement.getAsJsonObject().get(discriminatorField);
+ if (null == element) {
+ throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">");
+ }
+ return element.getAsString();
+ }
+
+ /**
+ * Returns the Java class that implements the OpenAPI schema for the specified discriminator value.
+ *
+ * @param classByDiscriminatorValue The map of discriminator values to Java classes.
+ * @param discriminatorValue The value of the OpenAPI discriminator in the input data.
+ * @return The Java class that implements the OpenAPI schema
+ */
+ private static Class getClassByDiscriminator(Map classByDiscriminatorValue, String discriminatorValue) {
+ Class clazz = (Class) classByDiscriminatorValue.get(discriminatorValue{{^discriminatorCaseSensitive}}.toUpperCase(Locale.ROOT){{/discriminatorCaseSensitive}});
+ if (null == clazz) {
+ throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">");
+ }
+ return clazz;
+ }
+
+ public JSON() {
+ gson = createGson()
+ .registerTypeAdapter(Date.class, dateTypeAdapter)
+ .registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter)
+ {{#joda}}
+ .registerTypeAdapter(DateTime.class, dateTimeTypeAdapter)
+ .registerTypeAdapter(LocalDate.class, localDateTypeAdapter)
+ {{/joda}}
+ {{#jsr310}}
+ .registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter)
+ .registerTypeAdapter(LocalDate.class, localDateTypeAdapter)
+ {{/jsr310}}
+ .registerTypeAdapter(byte[].class, byteArrayAdapter)
+ {{#models}}
+ {{#model}}
+ {{^isEnum}}
+ {{^hasChildren}}
+ .registerTypeAdapterFactory(new {{modelPackage}}.{{{classname}}}.CustomTypeAdapterFactory())
+ {{/hasChildren}}
+ {{/isEnum}}
+ {{/model}}
+ {{/models}}
+ .create();
+ }
+
+ /**
+ * Get Gson.
+ *
+ * @return Gson
+ */
+ public Gson getGson() {
+ return gson;
+ }
+
+ /**
+ * Set Gson.
+ *
+ * @param gson Gson
+ */
+ public void setGson(Gson gson) {
+ this.gson = gson;
+ }
+
+ public void setLenientOnJson(boolean lenientOnJson) {
+ isLenientOnJson = lenientOnJson;
+ }
+
+ /**
+ * Serialize the given Java object into JSON string.
+ *
+ * @param obj Object
+ * @return String representation of the JSON
+ */
+ public String serialize(Object obj) {
+ return gson.toJson(obj);
+ }
+
+ /**
+ * Deserialize the given JSON string to Java object.
+ *
+ * @param Type
+ * @param body The JSON string
+ * @param returnType The type to deserialize into
+ * @return The deserialized Java object
+ */
+ @SuppressWarnings("unchecked")
+ public T deserialize(String body, Type returnType) {
+ try {
+ if (isLenientOnJson) {
+ JsonReader jsonReader = new JsonReader(new StringReader(body));
+ // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean)
+ jsonReader.setLenient(true);
+ return gson.fromJson(jsonReader, returnType);
+ } else {
+ return gson.fromJson(body, returnType);
+ }
+ } catch (JsonParseException e) {
+ // Fallback processing when failed to parse JSON form response body:
+ // return the response body string directly for the String return type;
+ if (returnType.equals(String.class)) {
+ return (T) body;
+ } else {
+ throw (e);
+ }
+ }
+ }
+
+ /**
+ * Gson TypeAdapter for Byte Array type
+ */
+ public class ByteArrayAdapter extends TypeAdapter {
+
+ @Override
+ public void write(JsonWriter out, byte[] value) throws IOException {
+ if (value == null) {
+ out.nullValue();
+ } else {
+ out.value(ByteString.of(value).base64());
+ }
+ }
+
+ @Override
+ public byte[] read(JsonReader in) throws IOException {
+ switch (in.peek()) {
+ case NULL:
+ in.nextNull();
+ return null;
+ default:
+ String bytesAsBase64 = in.nextString();
+ ByteString byteString = ByteString.decodeBase64(bytesAsBase64);
+ return byteString.toByteArray();
+ }
+ }
+ }
+
+ {{#joda}}
+ /**
+ * Gson TypeAdapter for Joda DateTime type
+ */
+ public class DateTimeTypeAdapter extends TypeAdapter {
+
+ private DateTimeFormatter formatter;
+
+ public DateTimeTypeAdapter() {
+ this(new DateTimeFormatterBuilder()
+ .append(ISODateTimeFormat.dateTime().getPrinter(), ISODateTimeFormat.dateOptionalTimeParser().getParser())
+ .toFormatter());
+ }
+
+ public DateTimeTypeAdapter(DateTimeFormatter formatter) {
+ this.formatter = formatter;
+ }
+
+ public void setFormat(DateTimeFormatter dateFormat) {
+ this.formatter = dateFormat;
+ }
+
+ @Override
+ public void write(JsonWriter out, DateTime date) throws IOException {
+ if (date == null) {
+ out.nullValue();
+ } else {
+ out.value(formatter.print(date));
+ }
+ }
+
+ @Override
+ public DateTime read(JsonReader in) throws IOException {
+ switch (in.peek()) {
+ case NULL:
+ in.nextNull();
+ return null;
+ default:
+ String date = in.nextString();
+ return formatter.parseDateTime(date);
+ }
+ }
+ }
+
+ /**
+ * Gson TypeAdapter for Joda LocalDate type
+ */
+ public class LocalDateTypeAdapter extends TypeAdapter {
+
+ private DateTimeFormatter formatter;
+
+ public LocalDateTypeAdapter() {
+ this(ISODateTimeFormat.date());
+ }
+
+ public LocalDateTypeAdapter(DateTimeFormatter formatter) {
+ this.formatter = formatter;
+ }
+
+ public void setFormat(DateTimeFormatter dateFormat) {
+ this.formatter = dateFormat;
+ }
+
+ @Override
+ public void write(JsonWriter out, LocalDate date) throws IOException {
+ if (date == null) {
+ out.nullValue();
+ } else {
+ out.value(formatter.print(date));
+ }
+ }
+
+ @Override
+ public LocalDate read(JsonReader in) throws IOException {
+ switch (in.peek()) {
+ case NULL:
+ in.nextNull();
+ return null;
+ default:
+ String date = in.nextString();
+ return formatter.parseLocalDate(date);
+ }
+ }
+ }
+
+ public void setDateTimeFormat(DateTimeFormatter dateFormat) {
+ dateTimeTypeAdapter.setFormat(dateFormat);
+ }
+
+ public void setLocalDateFormat(DateTimeFormatter dateFormat) {
+ localDateTypeAdapter.setFormat(dateFormat);
+ }
+
+ {{/joda}}
+ {{#jsr310}}
+ /**
+ * Gson TypeAdapter for JSR310 OffsetDateTime type
+ */
+ public class OffsetDateTimeTypeAdapter extends TypeAdapter {
+
+ private DateTimeFormatter formatter;
+
+ public OffsetDateTimeTypeAdapter() {
+ this(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+ }
+
+ public OffsetDateTimeTypeAdapter(DateTimeFormatter formatter) {
+ this.formatter = formatter;
+ }
+
+ public void setFormat(DateTimeFormatter dateFormat) {
+ this.formatter = dateFormat;
+ }
+
+ @Override
+ public void write(JsonWriter out, OffsetDateTime date) throws IOException {
+ if (date == null) {
+ out.nullValue();
+ } else {
+ out.value(formatter.format(date));
+ }
+ }
+
+ @Override
+ public OffsetDateTime read(JsonReader in) throws IOException {
+ switch (in.peek()) {
+ case NULL:
+ in.nextNull();
+ return null;
+ default:
+ String date = in.nextString();
+ if (date.endsWith("+0000")) {
+ date = date.substring(0, date.length()-5) + "Z";
+ }
+ return OffsetDateTime.parse(date, formatter);
+ }
+ }
+ }
+
+ /**
+ * Gson TypeAdapter for JSR310 LocalDate type
+ */
+ public class LocalDateTypeAdapter extends TypeAdapter {
+
+ private DateTimeFormatter formatter;
+
+ public LocalDateTypeAdapter() {
+ this(DateTimeFormatter.ISO_LOCAL_DATE);
+ }
+
+ public LocalDateTypeAdapter(DateTimeFormatter formatter) {
+ this.formatter = formatter;
+ }
+
+ public void setFormat(DateTimeFormatter dateFormat) {
+ this.formatter = dateFormat;
+ }
+
+ @Override
+ public void write(JsonWriter out, LocalDate date) throws IOException {
+ if (date == null) {
+ out.nullValue();
+ } else {
+ out.value(formatter.format(date));
+ }
+ }
+
+ @Override
+ public LocalDate read(JsonReader in) throws IOException {
+ switch (in.peek()) {
+ case NULL:
+ in.nextNull();
+ return null;
+ default:
+ String date = in.nextString();
+ return LocalDate.parse(date, formatter);
+ }
+ }
+ }
+
+ public void setOffsetDateTimeFormat(DateTimeFormatter dateFormat) {
+ offsetDateTimeTypeAdapter.setFormat(dateFormat);
+ }
+
+ public void setLocalDateFormat(DateTimeFormatter dateFormat) {
+ localDateTypeAdapter.setFormat(dateFormat);
+ }
+
+ {{/jsr310}}
+ /**
+ * Gson TypeAdapter for java.sql.Date type
+ * If the dateFormat is null, a simple "yyyy-MM-dd" format will be used
+ * (more efficient than SimpleDateFormat).
+ */
+ public class SqlDateTypeAdapter extends TypeAdapter {
+
+ private DateFormat dateFormat;
+
+ public SqlDateTypeAdapter() {}
+
+ public SqlDateTypeAdapter(DateFormat dateFormat) {
+ this.dateFormat = dateFormat;
+ }
+
+ public void setFormat(DateFormat dateFormat) {
+ this.dateFormat = dateFormat;
+ }
+
+ @Override
+ public void write(JsonWriter out, java.sql.Date date) throws IOException {
+ if (date == null) {
+ out.nullValue();
+ } else {
+ String value;
+ if (dateFormat != null) {
+ value = dateFormat.format(date);
+ } else {
+ value = date.toString();
+ }
+ out.value(value);
+ }
+ }
+
+ @Override
+ public java.sql.Date read(JsonReader in) throws IOException {
+ switch (in.peek()) {
+ case NULL:
+ in.nextNull();
+ return null;
+ default:
+ String date = in.nextString();
+ try {
+ if (dateFormat != null) {
+ return new java.sql.Date(dateFormat.parse(date).getTime());
+ }
+ return new java.sql.Date(ISO8601Utils.parse(date, new ParsePosition(0)).getTime());
+ } catch (ParseException e) {
+ throw new JsonParseException(e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Gson TypeAdapter for java.util.Date type
+ * If the dateFormat is null, ISO8601Utils will be used.
+ */
+ public class DateTypeAdapter extends TypeAdapter {
+
+ private DateFormat dateFormat;
+
+ public DateTypeAdapter() {}
+
+ public DateTypeAdapter(DateFormat dateFormat) {
+ this.dateFormat = dateFormat;
+ }
+
+ public void setFormat(DateFormat dateFormat) {
+ this.dateFormat = dateFormat;
+ }
+
+ @Override
+ public void write(JsonWriter out, Date date) throws IOException {
+ if (date == null) {
+ out.nullValue();
+ } else {
+ String value;
+ if (dateFormat != null) {
+ value = dateFormat.format(date);
+ } else {
+ value = ISO8601Utils.format(date, true);
+ }
+ out.value(value);
+ }
+ }
+
+ @Override
+ public Date read(JsonReader in) throws IOException {
+ try {
+ switch (in.peek()) {
+ case NULL:
+ in.nextNull();
+ return null;
+ default:
+ String date = in.nextString();
+ try {
+ if (dateFormat != null) {
+ return dateFormat.parse(date);
+ }
+ return ISO8601Utils.parse(date, new ParsePosition(0));
+ } catch (ParseException e) {
+ throw new JsonParseException(e);
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ throw new JsonParseException(e);
+ }
+ }
+ }
+
+ public void setDateFormat(DateFormat dateFormat) {
+ dateTypeAdapter.setFormat(dateFormat);
+ }
+
+ public void setSqlDateFormat(DateFormat dateFormat) {
+ sqlDateTypeAdapter.setFormat(dateFormat);
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ProgressRequestBody.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ProgressRequestBody.mustache
new file mode 100644
index 00000000000..71e1e2b4cbe
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ProgressRequestBody.mustache
@@ -0,0 +1,62 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+import okhttp3.MediaType;
+import okhttp3.RequestBody;
+
+import java.io.IOException;
+
+import okio.Buffer;
+import okio.BufferedSink;
+import okio.ForwardingSink;
+import okio.Okio;
+import okio.Sink;
+
+public class ProgressRequestBody extends RequestBody {
+
+ private final RequestBody requestBody;
+
+ private final ApiCallback callback;
+
+ public ProgressRequestBody(RequestBody requestBody, ApiCallback callback) {
+ this.requestBody = requestBody;
+ this.callback = callback;
+ }
+
+ @Override
+ public MediaType contentType() {
+ return requestBody.contentType();
+ }
+
+ @Override
+ public long contentLength() throws IOException {
+ return requestBody.contentLength();
+ }
+
+ @Override
+ public void writeTo(BufferedSink sink) throws IOException {
+ BufferedSink bufferedSink = Okio.buffer(sink(sink));
+ requestBody.writeTo(bufferedSink);
+ bufferedSink.flush();
+ }
+
+ private Sink sink(Sink sink) {
+ return new ForwardingSink(sink) {
+
+ long bytesWritten = 0L;
+ long contentLength = 0L;
+
+ @Override
+ public void write(Buffer source, long byteCount) throws IOException {
+ super.write(source, byteCount);
+ if (contentLength == 0) {
+ contentLength = contentLength();
+ }
+
+ bytesWritten += byteCount;
+ callback.onUploadProgress(bytesWritten, contentLength, bytesWritten == contentLength);
+ }
+ };
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ProgressResponseBody.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ProgressResponseBody.mustache
new file mode 100644
index 00000000000..45115940b66
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/ProgressResponseBody.mustache
@@ -0,0 +1,59 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+import okhttp3.MediaType;
+import okhttp3.ResponseBody;
+
+import java.io.IOException;
+
+import okio.Buffer;
+import okio.BufferedSource;
+import okio.ForwardingSource;
+import okio.Okio;
+import okio.Source;
+
+public class ProgressResponseBody extends ResponseBody {
+
+ private final ResponseBody responseBody;
+ private final ApiCallback callback;
+ private BufferedSource bufferedSource;
+
+ public ProgressResponseBody(ResponseBody responseBody, ApiCallback callback) {
+ this.responseBody = responseBody;
+ this.callback = callback;
+ }
+
+ @Override
+ public MediaType contentType() {
+ return responseBody.contentType();
+ }
+
+ @Override
+ public long contentLength() {
+ return responseBody.contentLength();
+ }
+
+ @Override
+ public BufferedSource source() {
+ if (bufferedSource == null) {
+ bufferedSource = Okio.buffer(source(responseBody.source()));
+ }
+ return bufferedSource;
+ }
+
+ private Source source(Source source) {
+ return new ForwardingSource(source) {
+ long totalBytesRead = 0L;
+
+ @Override
+ public long read(Buffer sink, long byteCount) throws IOException {
+ long bytesRead = super.read(sink, byteCount);
+ // read() returns the number of bytes read, or -1 if this source is exhausted.
+ totalBytesRead += bytesRead != -1 ? bytesRead : 0;
+ callback.onDownloadProgress(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
+ return bytesRead;
+ }
+ };
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/README.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/README.mustache
new file mode 100644
index 00000000000..a1a142bd488
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/README.mustache
@@ -0,0 +1,183 @@
+# {{artifactId}}
+
+{{appName}}
+- API version: {{appVersion}}
+{{^hideGenerationTimestamp}}
+ - Build date: {{generatedDate}}
+{{/hideGenerationTimestamp}}
+
+{{{appDescriptionWithNewLines}}}
+
+{{#infoUrl}}
+ For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
+{{/infoUrl}}
+
+*Automatically generated by the [OpenAPI Generator](https://openapi-generator.tech)*
+
+
+## Requirements
+
+Building the API client library requires:
+1. Java {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}+
+2. Maven (3.8.3+)/Gradle (7.2+)
+
+## Installation
+
+To install the API client library to your local Maven repository, simply execute:
+
+```shell
+mvn clean install
+```
+
+To deploy it to a remote Maven repository instead, configure the settings of the repository and execute:
+
+```shell
+mvn clean deploy
+```
+
+Refer to the [OSSRH Guide](http://central.sonatype.org/pages/ossrh-guide.html) for more information.
+
+### Maven users
+
+Add this dependency to your project's POM:
+
+```xml
+
+ {{{groupId}}}
+ {{{artifactId}}}
+ {{{artifactVersion}}}
+ compile
+
+```
+
+### Gradle users
+
+Add this dependency to your project's build file:
+
+```groovy
+ repositories {
+ mavenCentral() // Needed if the '{{{artifactId}}}' jar has been published to maven central.
+ mavenLocal() // Needed if the '{{{artifactId}}}' jar has been published to the local maven repo.
+ }
+
+ dependencies {
+ implementation "{{{groupId}}}:{{{artifactId}}}:{{{artifactVersion}}}"
+ }
+```
+
+### Others
+
+At first generate the JAR by executing:
+
+```shell
+mvn clean package
+```
+
+Then manually install the following JARs:
+
+* `target/{{{artifactId}}}-{{{artifactVersion}}}.jar`
+* `target/lib/*.jar`
+
+## Getting Started
+
+Please follow the [installation](#installation) instruction and execute the following Java code:
+
+```java
+{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}
+// Import classes:
+import {{{invokerPackage}}}.ApiClient;
+import {{{invokerPackage}}}.ApiException;
+import {{{invokerPackage}}}.Configuration;{{#hasAuthMethods}}
+import {{{invokerPackage}}}.auth.*;{{/hasAuthMethods}}
+import {{{invokerPackage}}}.models.*;
+import {{{package}}}.{{{classname}}};
+
+public class Example {
+ public static void main(String[] args) {
+ ApiClient defaultClient = Configuration.getDefaultApiClient();
+ defaultClient.setBasePath("{{{basePath}}}");
+ {{#hasAuthMethods}}
+ {{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
+ // Configure HTTP basic authorization: {{{name}}}
+ HttpBasicAuth {{{name}}} = (HttpBasicAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setUsername("YOUR USERNAME");
+ {{{name}}}.setPassword("YOUR PASSWORD");{{/isBasicBasic}}{{#isBasicBearer}}
+ // Configure HTTP bearer authorization: {{{name}}}
+ HttpBearerAuth {{{name}}} = (HttpBearerAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setBearerToken("BEARER TOKEN");{{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}
+ // Configure API key authorization: {{{name}}}
+ ApiKeyAuth {{{name}}} = (ApiKeyAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setApiKey("YOUR API KEY");
+ // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
+ //{{{name}}}.setApiKeyPrefix("Token");{{/isApiKey}}{{#isOAuth}}
+ // Configure OAuth2 access token for authorization: {{{name}}}
+ OAuth {{{name}}} = (OAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setAccessToken("YOUR ACCESS TOKEN");{{/isOAuth}}
+ {{/authMethods}}
+ {{/hasAuthMethods}}
+
+ {{{classname}}} apiInstance = new {{{classname}}}(defaultClient);
+ {{#allParams}}
+ {{{dataType}}} {{{paramName}}} = {{{example}}}; // {{{dataType}}} | {{{description}}}
+ {{/allParams}}
+ try {
+ {{#returnType}}{{{.}}} result = {{/returnType}}apiInstance.{{{operationId}}}{{^vendorExtensions.x-group-parameters}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}});{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}({{#requiredParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}}
+ .{{{paramName}}}({{{paramName}}}){{/optionalParams}}
+ .execute();{{/vendorExtensions.x-group-parameters}}{{#returnType}}
+ System.out.println(result);{{/returnType}}
+ } catch (ApiException e) {
+ System.err.println("Exception when calling {{{classname}}}#{{{operationId}}}");
+ System.err.println("Status code: " + e.getCode());
+ System.err.println("Reason: " + e.getResponseBody());
+ System.err.println("Response headers: " + e.getResponseHeaders());
+ e.printStackTrace();
+ }
+ }
+}
+{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
+```
+
+## Documentation for API Endpoints
+
+All URIs are relative to *{{basePath}}*
+
+Class | Method | HTTP request | Description
+------------ | ------------- | ------------- | -------------
+{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{summary}}
+{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
+
+## Documentation for Models
+
+{{#models}}{{#model}} - [{{classname}}]({{modelDocPath}}{{classname}}.md)
+{{/model}}{{/models}}
+
+## Documentation for Authorization
+
+{{^authMethods}}All endpoints do not require authorization.
+{{/authMethods}}Authentication schemes defined for the API:
+{{#authMethods}}### {{name}}
+
+{{#isApiKey}}- **Type**: API key
+- **API key parameter name**: {{keyParamName}}
+- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
+{{/isApiKey}}
+{{#isBasic}}- **Type**: HTTP basic authentication
+{{/isBasic}}
+{{#isOAuth}}- **Type**: OAuth
+- **Flow**: {{flow}}
+- **Authorization URL**: {{authorizationUrl}}
+- **Scopes**: {{^scopes}}N/A{{/scopes}}
+{{#scopes}} - {{scope}}: {{description}}
+{{/scopes}}
+{{/isOAuth}}
+
+{{/authMethods}}
+
+## Recommendation
+
+It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues.
+
+## Author
+
+{{#apiInfo}}{{#apis}}{{#-last}}{{infoEmail}}
+{{/-last}}{{/apis}}{{/apiInfo}}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/anyof_model.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/anyof_model.mustache
new file mode 100644
index 00000000000..a4c5c86ca2d
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/anyof_model.mustache
@@ -0,0 +1,183 @@
+import javax.ws.rs.core.GenericType;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonParseException;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.annotations.JsonAdapter;
+import com.google.gson.annotations.SerializedName;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+
+import {{invokerPackage}}.JSON;
+
+{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>xmlAnnotation}}
+public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-implements}}, {{{.}}}{{/vendorExtensions.x-implements}} {
+ private static final Logger log = Logger.getLogger({{classname}}.class.getName());
+
+ public static class CustomTypeAdapterFactory implements TypeAdapterFactory {
+ @SuppressWarnings("unchecked")
+ @Override
+ public TypeAdapter create(Gson gson, TypeToken type) {
+ if (!{{classname}}.class.isAssignableFrom(type.getRawType())) {
+ return null; // this class only serializes '{{classname}}' and its subtypes
+ }
+ final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class);
+ {{#anyOf}}
+ final TypeAdapter<{{.}}> adapter{{.}} = gson.getDelegateAdapter(this, TypeToken.get({{.}}.class));
+ {{/anyOf}}
+
+ return (TypeAdapter) new TypeAdapter<{{classname}}>() {
+ @Override
+ public void write(JsonWriter out, {{classname}} value) throws IOException {
+ {{#anyOf}}
+ // check if the actual instance is of the type `{{.}}`
+ if (value.getActualInstance() instanceof {{.}}) {
+ JsonObject obj = adapter{{.}}.toJsonTree(({{.}})value.getActualInstance()).getAsJsonObject();
+ elementAdapter.write(out, obj);
+ }
+
+ {{/anyOf}}
+ throw new IOException("Failed to deserialize as the type doesn't match anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}");
+ }
+
+ @Override
+ public {{classname}} read(JsonReader in) throws IOException {
+ Object deserialized = null;
+ {{#useOneOfDiscriminatorLookup}}
+ {{#discriminator}}
+ // use discriminator value for faster anyOf lookup
+ {{classname}} new{{classname}} = new {{classname}}();
+ String discriminatorValue = elementAdapter.read(in).getAsJsonObject().get("{{{propertyBaseName}}}").getAsString();
+ switch (discriminatorValue) {
+ {{#mappedModels}}
+ case "{{{mappingName}}}":
+ deserialized = gson.fromJson(in, {{{modelName}}}.class);
+ new{{classname}}.setActualInstance(deserialized);
+ return new{{classname}};
+ {{/mappedModels}}
+ default:
+ log.log(Level.WARNING, String.format("Failed to lookup discriminator value `%s` for {{classname}}. Possible values:{{#mappedModels}} {{{mappingName}}}{{/mappedModels}}", discriminatorValue));
+ }
+
+ {{/discriminator}}
+ {{/useOneOfDiscriminatorLookup}}
+
+ {{#anyOf}}
+ // deserialize {{{.}}}
+ try {
+ deserialized = gson.fromJson(in, {{.}}.class);
+ log.log(Level.FINER, "Input data matches schema '{{{.}}}'");
+ {{classname}} ret = new {{classname}}();
+ ret.setActualInstance(deserialized);
+ return ret;
+ } catch (Exception e) {
+ // deserialization failed, continue
+ log.log(Level.FINER, "Input data does not match schema '{{{.}}}'", e);
+ }
+
+ {{/anyOf}}
+ throw new IOException("Failed deserialization for {{classname}}: no match found.");
+ }
+ }.nullSafe();
+ }
+ }
+
+ // store a list of schema names defined in anyOf
+ public static final Map schemas = new HashMap();
+
+ public {{classname}}() {
+ super("anyOf", {{#isNullable}}Boolean.TRUE{{/isNullable}}{{^isNullable}}Boolean.FALSE{{/isNullable}});
+ }
+
+ {{#anyOf}}
+ public {{classname}}({{{.}}} o) {
+ super("anyOf", {{#isNullable}}Boolean.TRUE{{/isNullable}}{{^isNullable}}Boolean.FALSE{{/isNullable}});
+ setActualInstance(o);
+ }
+
+ {{/anyOf}}
+ static {
+ {{#anyOf}}
+ schemas.put("{{{.}}}", new GenericType<{{{.}}}>() {
+ });
+ {{/anyOf}}
+ }
+
+ @Override
+ public Map getSchemas() {
+ return {{classname}}.schemas;
+ }
+
+ /**
+ * Set the instance that matches the anyOf child schema, check
+ * the instance parameter is valid against the anyOf child schemas:
+ * {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}
+ *
+ * It could be an instance of the 'anyOf' schemas.
+ * The anyOf child schemas may themselves be a composed schema (allOf, anyOf, anyOf).
+ */
+ @Override
+ public void setActualInstance(Object instance) {
+ {{#isNullable}}
+ if (instance == null) {
+ super.setActualInstance(instance);
+ return;
+ }
+
+ {{/isNullable}}
+ {{#anyOf}}
+ if (instance instanceof {{{.}}}) {
+ super.setActualInstance(instance);
+ return;
+ }
+
+ {{/anyOf}}
+ throw new RuntimeException("Invalid instance type. Must be {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}");
+ }
+
+ /**
+ * Get the actual instance, which can be the following:
+ * {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}
+ *
+ * @return The actual instance ({{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}})
+ */
+ @Override
+ public Object getActualInstance() {
+ return super.getActualInstance();
+ }
+
+ {{#anyOf}}
+ /**
+ * Get the actual instance of `{{{.}}}`. If the actual instance is not `{{{.}}}`,
+ * the ClassCastException will be thrown.
+ *
+ * @return The actual instance of `{{{.}}}`
+ * @throws ClassCastException if the instance is not `{{{.}}}`
+ */
+ public {{{.}}} get{{{.}}}() throws ClassCastException {
+ return ({{{.}}})super.getActualInstance();
+ }
+
+ {{/anyOf}}
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api.mustache
new file mode 100644
index 00000000000..525d56fa5d5
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api.mustache
@@ -0,0 +1,500 @@
+{{>licenseInfo}}
+
+package {{package}};
+
+import {{invokerPackage}}.ApiCallback;
+import {{invokerPackage}}.ApiClient;
+import {{invokerPackage}}.ApiException;
+{{#dynamicOperations}}
+import {{invokerPackage}}.ApiOperation;
+{{/dynamicOperations}}
+import {{invokerPackage}}.ApiResponse;
+import {{invokerPackage}}.Configuration;
+import {{invokerPackage}}.Pair;
+import {{invokerPackage}}.ProgressRequestBody;
+import {{invokerPackage}}.ProgressResponseBody;
+{{#performBeanValidation}}
+import {{invokerPackage}}.BeanValidationException;
+{{/performBeanValidation}}
+
+import com.google.gson.reflect.TypeToken;
+{{#dynamicOperations}}
+import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.parameters.Parameter;
+{{/dynamicOperations}}
+
+import java.io.IOException;
+
+{{#useBeanValidation}}
+import javax.validation.constraints.*;
+{{/useBeanValidation}}
+{{#performBeanValidation}}
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.ValidatorFactory;
+import javax.validation.executable.ExecutableValidator;
+import java.util.Set;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+{{/performBeanValidation}}
+
+{{#imports}}import {{import}};
+{{/imports}}
+
+import java.lang.reflect.Type;
+{{^fullJavaUtil}}
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+{{#supportStreaming}}
+import java.io.InputStream;
+{{/supportStreaming}}
+{{/fullJavaUtil}}
+
+{{#operations}}
+public class {{classname}} {
+ private ApiClient localVarApiClient;
+
+ public {{classname}}() {
+ this(Configuration.getDefaultApiClient());
+ }
+
+ public {{classname}}(ApiClient apiClient) {
+ this.localVarApiClient = apiClient;
+ }
+
+ public ApiClient getApiClient() {
+ return localVarApiClient;
+ }
+
+ public void setApiClient(ApiClient apiClient) {
+ this.localVarApiClient = apiClient;
+ }
+
+ {{#operation}}
+ {{^vendorExtensions.x-group-parameters}}/**
+ * Build call for {{operationId}}{{#allParams}}
+ * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}
+ * @param _callback Callback for upload/download progress
+ * @return Call to execute
+ * @throws ApiException If fail to serialize the request body object
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ {{#externalDocs}}
+ * {{description}}
+ * @see {{summary}} Documentation
+ {{/externalDocs}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}private{{/vendorExtensions.x-group-parameters}} okhttp3.Call {{operationId}}Call({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ApiCallback _callback) throws ApiException {
+ Object localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
+
+ // create path and map variables
+ {{^dynamicOperations}}
+ String localVarPath = "{{{path}}}"{{#pathParams}}
+ .replaceAll("\\{" + "{{baseName}}" + "\\}", localVarApiClient.escapeString({{#collectionFormat}}localVarApiClient.collectionPathParameterToString("{{{collectionFormat}}}", {{{paramName}}}){{/collectionFormat}}{{^collectionFormat}}{{{paramName}}}.toString(){{/collectionFormat}})){{/pathParams}};
+ {{/dynamicOperations}}
+ {{#dynamicOperations}}
+ ApiOperation apiOperation = localVarApiClient.getOperationLookupMap().get("{{{operationId}}}");
+ if (apiOperation == null) {
+ throw new ApiException("Operation not found in OAS");
+ }
+ Operation operation = apiOperation.getOperation();
+ String localVarPath = apiOperation.getPath();
+ Map paramMap = new HashMap<>();
+ {{#allParams}}
+ {{^isFormParam}}
+ {{^isBodyParam}}
+ paramMap.put("{{baseName}}", {{paramName}});
+ {{/isBodyParam}}
+ {{/isFormParam}}
+ {{/allParams}}
+ {{/dynamicOperations}}
+
+ {{javaUtilPrefix}}List localVarQueryParams = new {{javaUtilPrefix}}ArrayList();
+ {{javaUtilPrefix}}List localVarCollectionQueryParams = new {{javaUtilPrefix}}ArrayList();
+ {{javaUtilPrefix}}Map localVarHeaderParams = new {{javaUtilPrefix}}HashMap();
+ {{javaUtilPrefix}}Map localVarCookieParams = new {{javaUtilPrefix}}HashMap();
+ {{javaUtilPrefix}}Map localVarFormParams = new {{javaUtilPrefix}}HashMap();
+
+ {{#formParams}}
+ if ({{paramName}} != null) {
+ localVarFormParams.put("{{baseName}}", {{paramName}});
+ }
+
+ {{/formParams}}
+ {{^dynamicOperations}}
+ {{#queryParams}}
+ if ({{paramName}} != null) {
+ {{#collectionFormat}}localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("{{{.}}}", {{/collectionFormat}}{{^collectionFormat}}localVarQueryParams.addAll(localVarApiClient.parameterToPair({{/collectionFormat}}"{{baseName}}", {{paramName}}));
+ }
+
+ {{/queryParams}}
+ {{#headerParams}}
+ if ({{paramName}} != null) {
+ localVarHeaderParams.put("{{baseName}}", localVarApiClient.parameterToString({{paramName}}));
+ }
+
+ {{/headerParams}}
+ {{#cookieParams}}
+ if ({{paramName}} != null) {
+ localVarCookieParams.put("{{baseName}}", localVarApiClient.parameterToString({{paramName}}));
+ }
+
+ {{/cookieParams}}
+ {{/dynamicOperations}}
+ {{#dynamicOperations}}
+ localVarPath = localVarApiClient.fillParametersFromOperation(operation, paramMap, localVarPath, localVarQueryParams, localVarCollectionQueryParams, localVarHeaderParams, localVarCookieParams);
+
+ {{/dynamicOperations}}
+ final String[] localVarAccepts = {
+ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}}
+ };
+ final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts);
+ if (localVarAccept != null) {
+ localVarHeaderParams.put("Accept", localVarAccept);
+ }
+
+ final String[] localVarContentTypes = {
+ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}}
+ };
+ final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes);
+ if (localVarHeaderParams != null) {
+ localVarHeaderParams.put("Content-Type", localVarContentType);
+ }
+
+ String[] localVarAuthNames = new String[] { {{#authMethods}}"{{name}}"{{^-last}}, {{/-last}}{{/authMethods}} };
+ return localVarApiClient.buildCall(localVarPath, {{^dynamicOperations}}"{{httpMethod}}"{{/dynamicOperations}}{{#dynamicOperations}}apiOperation.getMethod(){{/dynamicOperations}}, localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback);
+ }
+
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ @SuppressWarnings("rawtypes")
+ private okhttp3.Call {{operationId}}ValidateBeforeCall({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ApiCallback _callback) throws ApiException {
+ {{^performBeanValidation}}
+ {{#allParams}}{{#required}}
+ // verify the required parameter '{{paramName}}' is set
+ if ({{paramName}} == null) {
+ throw new ApiException("Missing the required parameter '{{paramName}}' when calling {{operationId}}(Async)");
+ }
+ {{/required}}{{/allParams}}
+
+ okhttp3.Call localVarCall = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}_callback);
+ return localVarCall;
+
+ {{/performBeanValidation}}
+ {{#performBeanValidation}}
+ try {
+ ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ ExecutableValidator executableValidator = factory.getValidator().forExecutables();
+
+ Object[] parameterValues = { {{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}} };
+ Method method = this.getClass().getMethod("{{operationId}}WithHttpInfo"{{#allParams}}, {{#isArray}}java.util.List{{/isArray}}{{#isMap}}java.util.Map{{/isMap}}{{^isArray}}{{^isMap}}{{{dataType}}}{{/isMap}}{{/isArray}}.class{{/allParams}});
+ Set> violations = executableValidator.validateParameters(this, method,
+ parameterValues);
+
+ if (violations.size() == 0) {
+ okhttp3.Call localVarCall = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}_callback);
+ return localVarCall;
+
+ } else {
+ throw new BeanValidationException((Set) violations);
+ }
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ throw new ApiException(e.getMessage());
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ throw new ApiException(e.getMessage());
+ }
+
+ {{/performBeanValidation}}
+ }
+
+ {{^vendorExtensions.x-group-parameters}}
+ /**
+ * {{summary}}
+ * {{notes}}{{#allParams}}
+ * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}{{#returnType}}
+ * @return {{.}}{{/returnType}}
+ * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ {{#externalDocs}}
+ * {{description}}
+ * @see {{summary}} Documentation
+ {{/externalDocs}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ {{#vendorExtensions.x-streaming}}
+ public {{#returnType}}InputStream {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException {
+ {{#returnType}}InputStream localVarResp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{#returnType}}
+ return localVarResp;{{/returnType}}
+ }
+ {{/vendorExtensions.x-streaming}}
+ {{^vendorExtensions.x-streaming}}
+ public {{#returnType}}{{{.}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException {
+ {{#returnType}}ApiResponse<{{{.}}}> localVarResp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{#returnType}}
+ return localVarResp.getData();{{/returnType}}
+ }
+ {{/vendorExtensions.x-streaming}}
+ {{/vendorExtensions.x-group-parameters}}
+
+ {{^vendorExtensions.x-group-parameters}}/**
+ * {{summary}}
+ * {{notes}}{{#allParams}}
+ * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}
+ * @return ApiResponse<{{returnType}}{{^returnType}}Void{{/returnType}}>
+ * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ {{#externalDocs}}
+ * {{description}}
+ * @see {{summary}} Documentation
+ {{/externalDocs}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}private{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-streaming}} InputStream {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException {
+ okhttp3.Call localVarCall = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}null);
+ {{#returnType}}Type localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType();
+ return localVarApiClient.executeStream(localVarCall, localVarReturnType);{{/returnType}}
+ }
+ {{/vendorExtensions.x-streaming}}{{^vendorExtensions.x-streaming}} ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException {
+ okhttp3.Call localVarCall = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}null);
+ {{#returnType}}Type localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType();
+ return localVarApiClient.execute(localVarCall, localVarReturnType);{{/returnType}}{{^returnType}}return localVarApiClient.execute(localVarCall);{{/returnType}}
+ }
+ {{/vendorExtensions.x-streaming}}
+
+ {{^vendorExtensions.x-group-parameters}}/**
+ * {{summary}} (asynchronously)
+ * {{notes}}{{#allParams}}
+ * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}
+ * @param _callback The callback to be executed when the API call finishes
+ * @return The request call
+ * @throws ApiException If fail to process the API call, e.g. serializing the request body object
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ {{#externalDocs}}
+ * {{description}}
+ * @see {{summary}} Documentation
+ {{/externalDocs}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}private{{/vendorExtensions.x-group-parameters}} okhttp3.Call {{operationId}}Async({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ApiCallback<{{{returnType}}}{{^returnType}}Void{{/returnType}}> _callback) throws ApiException {
+
+ okhttp3.Call localVarCall = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}_callback);
+ {{#returnType}}Type localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType();
+ localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback);{{/returnType}}{{^returnType}}localVarApiClient.executeAsync(localVarCall, _callback);{{/returnType}}
+ return localVarCall;
+ }
+ {{#vendorExtensions.x-group-parameters}}
+
+ public class API{{operationId}}Request {
+ {{#requiredParams}}
+ private final {{{dataType}}} {{paramName}};
+ {{/requiredParams}}
+ {{#optionalParams}}
+ private {{{dataType}}} {{paramName}};
+ {{/optionalParams}}
+
+ private API{{operationId}}Request({{#requiredParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}) {
+ {{#requiredParams}}
+ this.{{paramName}} = {{paramName}};
+ {{/requiredParams}}
+ }
+
+ {{#optionalParams}}
+ /**
+ * Set {{paramName}}
+ * @param {{paramName}} {{description}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}})
+ * @return API{{operationId}}Request
+ */
+ public API{{operationId}}Request {{paramName}}({{{dataType}}} {{paramName}}) {
+ this.{{paramName}} = {{paramName}};
+ return this;
+ }
+
+ {{/optionalParams}}
+ /**
+ * Build call for {{operationId}}
+ * @param _callback ApiCallback API callback
+ * @return Call to execute
+ * @throws ApiException If fail to serialize the request body object
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException {
+ return {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}_callback);
+ }
+
+ /**
+ * Execute {{operationId}} request{{#returnType}}
+ * @return {{.}}{{/returnType}}
+ * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public {{{returnType}}}{{^returnType}}void{{/returnType}} execute() throws ApiException {
+ {{#returnType}}ApiResponse<{{{.}}}> localVarResp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{#returnType}}
+ return localVarResp.getData();{{/returnType}}
+ }
+
+ /**
+ * Execute {{operationId}} request with HTTP info returned
+ * @return ApiResponse<{{returnType}}{{^returnType}}Void{{/returnType}}>
+ * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public ApiResponse<{{{returnType}}}{{^returnType}}Void{{/returnType}}> executeWithHttpInfo() throws ApiException {
+ return {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
+ }
+
+ /**
+ * Execute {{operationId}} request (asynchronously)
+ * @param _callback The callback to be executed when the API call finishes
+ * @return The request call
+ * @throws ApiException If fail to process the API call, e.g. serializing the request body object
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public okhttp3.Call executeAsync(final ApiCallback<{{{returnType}}}{{^returnType}}Void{{/returnType}}> _callback) throws ApiException {
+ return {{operationId}}Async({{#allParams}}{{paramName}}, {{/allParams}}_callback);
+ }
+ }
+
+ /**
+ * {{summary}}
+ * {{notes}}{{#requiredParams}}
+ * @param {{paramName}} {{description}} (required){{/requiredParams}}
+ * @return API{{operationId}}Request
+ {{#responses.0}}
+ * @http.response.details
+
+ Status Code Description Response Headers
+ {{#responses}}
+ {{code}} {{message}} {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}}
+ {{/responses}}
+
+ {{/responses.0}}
+ {{#isDeprecated}}
+ * @deprecated
+ {{/isDeprecated}}
+ {{#externalDocs}}
+ * {{description}}
+ * @see {{summary}} Documentation
+ {{/externalDocs}}
+ */
+ {{#isDeprecated}}
+ @Deprecated
+ {{/isDeprecated}}
+ public API{{operationId}}Request {{operationId}}({{#requiredParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}) {
+ return new API{{operationId}}Request({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}});
+ }
+ {{/vendorExtensions.x-group-parameters}}
+ {{/operation}}
+}
+{{/operations}}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/apiException.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/apiException.mustache
new file mode 100644
index 00000000000..4bec51da938
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/apiException.mustache
@@ -0,0 +1,159 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}};
+
+import java.util.Map;
+import java.util.List;
+{{#caseInsensitiveResponseHeaders}}
+import java.util.Map.Entry;
+import java.util.TreeMap;
+{{/caseInsensitiveResponseHeaders}}
+
+/**
+ * ApiException class.
+ */
+@SuppressWarnings("serial")
+{{>generatedAnnotation}}
+public class ApiException extends{{#useRuntimeException}} RuntimeException {{/useRuntimeException}}{{^useRuntimeException}} Exception {{/useRuntimeException}}{
+ private int code = 0;
+ private Map> responseHeaders = null;
+ private String responseBody = null;
+
+ /**
+ * Constructor for ApiException.
+ */
+ public ApiException() {}
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param throwable a {@link java.lang.Throwable} object
+ */
+ public ApiException(Throwable throwable) {
+ super(throwable);
+ }
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param message the error message
+ */
+ public ApiException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param message the error message
+ * @param throwable a {@link java.lang.Throwable} object
+ * @param code HTTP status code
+ * @param responseHeaders a {@link java.util.Map} of HTTP response headers
+ * @param responseBody the response body
+ */
+ public ApiException(String message, Throwable throwable, int code, Map> responseHeaders, String responseBody) {
+ super(message, throwable);
+ this.code = code;
+ {{#caseInsensitiveResponseHeaders}}
+ Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER);
+ for(Entry> entry : responseHeaders.entrySet()){
+ headers.put(entry.getKey().toLowerCase(), entry.getValue());
+ }
+ {{/caseInsensitiveResponseHeaders}}
+ this.responseHeaders = {{#caseInsensitiveResponseHeaders}}headers{{/caseInsensitiveResponseHeaders}}{{^caseInsensitiveResponseHeaders}}responseHeaders{{/caseInsensitiveResponseHeaders}};
+ this.responseBody = responseBody;
+ }
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param message the error message
+ * @param code HTTP status code
+ * @param responseHeaders a {@link java.util.Map} of HTTP response headers
+ * @param responseBody the response body
+ */
+ public ApiException(String message, int code, Map> responseHeaders, String responseBody) {
+ this(message, (Throwable) null, code, responseHeaders, responseBody);
+ }
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param message the error message
+ * @param throwable a {@link java.lang.Throwable} object
+ * @param code HTTP status code
+ * @param responseHeaders a {@link java.util.Map} of HTTP response headers
+ */
+ public ApiException(String message, Throwable throwable, int code, Map> responseHeaders) {
+ this(message, throwable, code, responseHeaders, null);
+ }
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param code HTTP status code
+ * @param responseHeaders a {@link java.util.Map} of HTTP response headers
+ * @param responseBody the response body
+ */
+ public ApiException(int code, Map> responseHeaders, String responseBody) {
+ this((String) null, (Throwable) null, code, responseHeaders, responseBody);
+ }
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param code HTTP status code
+ * @param message a {@link java.lang.String} object
+ */
+ public ApiException(int code, String message) {
+ super(message);
+ this.code = code;
+ }
+
+ /**
+ * Constructor for ApiException.
+ *
+ * @param code HTTP status code
+ * @param message the error message
+ * @param responseHeaders a {@link java.util.Map} of HTTP response headers
+ * @param responseBody the response body
+ */
+ public ApiException(int code, String message, Map> responseHeaders, String responseBody) {
+ this(code, message);
+ {{#caseInsensitiveResponseHeaders}}
+ Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER);
+ for(Entry> entry : responseHeaders.entrySet()){
+ headers.put(entry.getKey().toLowerCase(), entry.getValue());
+ }
+ {{/caseInsensitiveResponseHeaders}}
+ this.responseHeaders = {{#caseInsensitiveResponseHeaders}}headers{{/caseInsensitiveResponseHeaders}}{{^caseInsensitiveResponseHeaders}}responseHeaders{{/caseInsensitiveResponseHeaders}};
+ this.responseBody = responseBody;
+ }
+
+ /**
+ * Get the HTTP status code.
+ *
+ * @return HTTP status code
+ */
+ public int getCode() {
+ return code;
+ }
+
+ /**
+ * Get the HTTP response headers.
+ *
+ * @return A map of list of string
+ */
+ public Map> getResponseHeaders() {
+ return responseHeaders;
+ }
+
+ /**
+ * Get the HTTP response body.
+ *
+ * @return Response body in the form of string
+ */
+ public String getResponseBody() {
+ return responseBody;
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api_doc.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api_doc.mustache
new file mode 100644
index 00000000000..5a4e3969c93
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api_doc.mustache
@@ -0,0 +1,106 @@
+# {{classname}}{{#description}}
+{{.}}{{/description}}
+
+All URIs are relative to *{{basePath}}*
+
+Method | HTTP request | Description
+------------- | ------------- | -------------
+{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{summary}}
+{{/operation}}{{/operations}}
+
+{{#operations}}
+{{#operation}}
+
+# **{{operationId}}**{{^vendorExtensions.x-group-parameters}}
+> {{#returnType}}{{.}} {{/returnType}}{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}){{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}
+> {{#returnType}}{{.}} {{/returnType}}{{operationId}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}}.{{paramName}}({{paramName}}){{/optionalParams}}.execute();{{/vendorExtensions.x-group-parameters}}
+
+{{summary}}{{#notes}}
+
+{{.}}{{/notes}}
+
+### Example
+```java
+// Import classes:
+import {{{invokerPackage}}}.ApiClient;
+import {{{invokerPackage}}}.ApiException;
+import {{{invokerPackage}}}.Configuration;{{#hasAuthMethods}}
+import {{{invokerPackage}}}.auth.*;{{/hasAuthMethods}}
+import {{{invokerPackage}}}.models.*;
+import {{{package}}}.{{{classname}}};
+
+public class Example {
+ public static void main(String[] args) {
+ ApiClient defaultClient = Configuration.getDefaultApiClient();
+ defaultClient.setBasePath("{{{basePath}}}");
+ {{#hasAuthMethods}}
+ {{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
+ // Configure HTTP basic authorization: {{{name}}}
+ HttpBasicAuth {{{name}}} = (HttpBasicAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setUsername("YOUR USERNAME");
+ {{{name}}}.setPassword("YOUR PASSWORD");{{/isBasicBasic}}{{#isBasicBearer}}
+ // Configure HTTP bearer authorization: {{{name}}}
+ HttpBearerAuth {{{name}}} = (HttpBearerAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setBearerToken("BEARER TOKEN");{{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}
+ // Configure API key authorization: {{{name}}}
+ ApiKeyAuth {{{name}}} = (ApiKeyAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setApiKey("YOUR API KEY");
+ // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
+ //{{{name}}}.setApiKeyPrefix("Token");{{/isApiKey}}{{#isOAuth}}
+ // Configure OAuth2 access token for authorization: {{{name}}}
+ OAuth {{{name}}} = (OAuth) defaultClient.getAuthentication("{{{name}}}");
+ {{{name}}}.setAccessToken("YOUR ACCESS TOKEN");{{/isOAuth}}
+ {{/authMethods}}
+ {{/hasAuthMethods}}
+
+ {{{classname}}} apiInstance = new {{{classname}}}(defaultClient);
+ {{#allParams}}
+ {{{dataType}}} {{{paramName}}} = {{{example}}}; // {{{dataType}}} | {{{description}}}
+ {{/allParams}}
+ try {
+ {{#returnType}}{{{.}}} result = {{/returnType}}apiInstance.{{{operationId}}}{{^vendorExtensions.x-group-parameters}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}});{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}({{#requiredParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}}
+ .{{{paramName}}}({{{paramName}}}){{/optionalParams}}
+ .execute();{{/vendorExtensions.x-group-parameters}}{{#returnType}}
+ System.out.println(result);{{/returnType}}
+ } catch (ApiException e) {
+ System.err.println("Exception when calling {{{classname}}}#{{{operationId}}}");
+ System.err.println("Status code: " + e.getCode());
+ System.err.println("Reason: " + e.getResponseBody());
+ System.err.println("Response headers: " + e.getResponseHeaders());
+ e.printStackTrace();
+ }
+ }
+}
+```
+
+### Parameters
+{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}
+{{#allParams}} **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} |{{^required}} [optional]{{/required}}{{^isContainer}}{{#defaultValue}} [default to {{.}}]{{/defaultValue}}{{/isContainer}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}]{{/allowableValues}}
+{{/allParams}}
+
+### Return type
+
+{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{returnType}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}}
+
+### Authorization
+
+{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{name}}](../README.md#{{name}}){{^-last}}, {{/-last}}{{/authMethods}}
+
+### HTTP request headers
+
+ - **Content-Type**: {{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
+ - **Accept**: {{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}{{^produces}}Not defined{{/produces}}
+
+{{#responses.0}}
+### HTTP response details
+| Status code | Description | Response headers |
+|-------------|-------------|------------------|
+{{#responses}}
+**{{code}}** | {{message}} | {{#headers}} * {{baseName}} - {{description}} {{/headers}}{{^headers.0}} - {{/headers.0}} |
+{{/responses}}
+{{/responses.0}}
+
+{{/operation}}
+{{/operations}}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api_test.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api_test.mustache
new file mode 100644
index 00000000000..98a30a60cd5
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/api_test.mustache
@@ -0,0 +1,56 @@
+{{>licenseInfo}}
+
+package {{package}};
+
+import {{invokerPackage}}.ApiException;
+{{#imports}}import {{import}};
+{{/imports}}
+import org.junit.Test;
+import org.junit.Ignore;
+
+{{^fullJavaUtil}}
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+{{#supportStreaming}}
+import java.io.InputStream;
+{{/supportStreaming}}
+{{/fullJavaUtil}}
+
+/**
+ * API tests for {{classname}}
+ */
+@Ignore
+public class {{classname}}Test {
+
+ private final {{classname}} api = new {{classname}}();
+
+ {{#operations}}{{#operation}}
+ /**
+ * {{summary}}
+ *
+ * {{notes}}
+ *
+ * @throws ApiException
+ * if the Api call fails
+ */
+ @Test
+ public void {{operationId}}Test() throws ApiException {
+ {{#allParams}}
+ {{{dataType}}} {{paramName}} = null;
+ {{/allParams}}
+ {{#vendorExtensions.x-streaming}}
+ InputStream response = api.{{operationId}}{{^vendorExtensions.x-group-parameters}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}}
+ .{{paramName}}({{paramName}}){{/optionalParams}}
+ .execute();{{/vendorExtensions.x-group-parameters}}
+ {{/vendorExtensions.x-streaming}}
+ {{^vendorExtensions.x-streaming}}
+ {{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}{{^vendorExtensions.x-group-parameters}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}){{#optionalParams}}
+ .{{paramName}}({{paramName}}){{/optionalParams}}
+ .execute();{{/vendorExtensions.x-group-parameters}}
+ {{/vendorExtensions.x-streaming}}
+ // TODO: test validations
+ }
+ {{/operation}}{{/operations}}
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/ApiKeyAuth.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/ApiKeyAuth.mustache
new file mode 100644
index 00000000000..a0dda669a89
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/ApiKeyAuth.mustache
@@ -0,0 +1,69 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}}.auth;
+
+import {{invokerPackage}}.ApiException;
+import {{invokerPackage}}.Pair;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.List;
+
+{{>generatedAnnotation}}
+public class ApiKeyAuth implements Authentication {
+ private final String location;
+ private final String paramName;
+
+ private String apiKey;
+ private String apiKeyPrefix;
+
+ public ApiKeyAuth(String location, String paramName) {
+ this.location = location;
+ this.paramName = paramName;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public String getParamName() {
+ return paramName;
+ }
+
+ public String getApiKey() {
+ return apiKey;
+ }
+
+ public void setApiKey(String apiKey) {
+ this.apiKey = apiKey;
+ }
+
+ public String getApiKeyPrefix() {
+ return apiKeyPrefix;
+ }
+
+ public void setApiKeyPrefix(String apiKeyPrefix) {
+ this.apiKeyPrefix = apiKeyPrefix;
+ }
+
+ @Override
+ public void applyToParams(List queryParams, Map headerParams, Map cookieParams,
+ String payload, String method, URI uri) throws ApiException {
+ if (apiKey == null) {
+ return;
+ }
+ String value;
+ if (apiKeyPrefix != null) {
+ value = apiKeyPrefix + " " + apiKey;
+ } else {
+ value = apiKey;
+ }
+ if ("query".equals(location)) {
+ queryParams.add(new Pair(paramName, value));
+ } else if ("header".equals(location)) {
+ headerParams.put(paramName, value);
+ } else if ("cookie".equals(location)) {
+ cookieParams.put(paramName, value);
+ }
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/Authentication.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/Authentication.mustache
new file mode 100644
index 00000000000..c4ad338c793
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/Authentication.mustache
@@ -0,0 +1,25 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}}.auth;
+
+import {{invokerPackage}}.Pair;
+import {{invokerPackage}}.ApiException;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.List;
+
+public interface Authentication {
+ /**
+ * Apply authentication settings to header and query params.
+ *
+ * @param queryParams List of query parameters
+ * @param headerParams Map of header parameters
+ * @param cookieParams Map of cookie parameters
+ * @param payload HTTP request body
+ * @param method HTTP method
+ * @param uri URI
+ * @throws ApiException if failed to update the parameters
+ */
+ void applyToParams(List queryParams, Map headerParams, Map cookieParams, String payload, String method, URI uri) throws ApiException;
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/HttpBasicAuth.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/HttpBasicAuth.mustache
new file mode 100644
index 00000000000..417a89e34cc
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/HttpBasicAuth.mustache
@@ -0,0 +1,46 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}}.auth;
+
+import {{invokerPackage}}.Pair;
+import {{invokerPackage}}.ApiException;
+
+import okhttp3.Credentials;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.List;
+
+import java.io.UnsupportedEncodingException;
+
+public class HttpBasicAuth implements Authentication {
+ private String username;
+ private String password;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @Override
+ public void applyToParams(List queryParams, Map headerParams, Map cookieParams,
+ String payload, String method, URI uri) throws ApiException {
+ if (username == null && password == null) {
+ return;
+ }
+ headerParams.put("Authorization", Credentials.basic(
+ username == null ? "" : username,
+ password == null ? "" : password));
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/HttpBearerAuth.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/HttpBearerAuth.mustache
new file mode 100644
index 00000000000..c8a9fce2965
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/HttpBearerAuth.mustache
@@ -0,0 +1,52 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}}.auth;
+
+import {{invokerPackage}}.ApiException;
+import {{invokerPackage}}.Pair;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.List;
+
+{{>generatedAnnotation}}
+public class HttpBearerAuth implements Authentication {
+ private final String scheme;
+ private String bearerToken;
+
+ public HttpBearerAuth(String scheme) {
+ this.scheme = scheme;
+ }
+
+ /**
+ * Gets the token, which together with the scheme, will be sent as the value of the Authorization header.
+ *
+ * @return The bearer token
+ */
+ public String getBearerToken() {
+ return bearerToken;
+ }
+
+ /**
+ * Sets the token, which together with the scheme, will be sent as the value of the Authorization header.
+ *
+ * @param bearerToken The bearer token to send in the Authorization header
+ */
+ public void setBearerToken(String bearerToken) {
+ this.bearerToken = bearerToken;
+ }
+
+ @Override
+ public void applyToParams(List queryParams, Map headerParams, Map cookieParams,
+ String payload, String method, URI uri) throws ApiException {
+ if (bearerToken == null) {
+ return;
+ }
+
+ headerParams.put("Authorization", (scheme != null ? upperCaseBearer(scheme) + " " : "") + bearerToken);
+ }
+
+ private static String upperCaseBearer(String scheme) {
+ return ("bearer".equalsIgnoreCase(scheme)) ? "Bearer" : scheme;
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/OAuth.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/OAuth.mustache
new file mode 100644
index 00000000000..34d35985718
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/OAuth.mustache
@@ -0,0 +1,31 @@
+{{>licenseInfo}}
+
+package {{invokerPackage}}.auth;
+
+import {{invokerPackage}}.Pair;
+import {{invokerPackage}}.ApiException;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.List;
+
+{{>generatedAnnotation}}
+public class OAuth implements Authentication {
+ private String accessToken;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ @Override
+ public void applyToParams(List queryParams, Map headerParams, Map cookieParams,
+ String payload, String method, URI uri) throws ApiException {
+ if (accessToken != null) {
+ headerParams.put("Authorization", "Bearer " + accessToken);
+ }
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/OAuthOkHttpClient.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/OAuthOkHttpClient.mustache
new file mode 100644
index 00000000000..cb0e8250550
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/OAuthOkHttpClient.mustache
@@ -0,0 +1,70 @@
+{{#hasOAuthMethods}}
+package {{invokerPackage}}.auth;
+
+import okhttp3.OkHttpClient;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import org.apache.oltu.oauth2.client.HttpClient;
+import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
+import org.apache.oltu.oauth2.client.response.OAuthClientResponse;
+import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class OAuthOkHttpClient implements HttpClient {
+ private OkHttpClient client;
+
+ public OAuthOkHttpClient() {
+ this.client = new OkHttpClient();
+ }
+
+ public OAuthOkHttpClient(OkHttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public T execute(OAuthClientRequest request, Map headers,
+ String requestMethod, Class responseClass)
+ throws OAuthSystemException, OAuthProblemException {
+
+ MediaType mediaType = MediaType.parse("application/json");
+ Request.Builder requestBuilder = new Request.Builder().url(request.getLocationUri());
+
+ if(headers != null) {
+ for (Entry entry : headers.entrySet()) {
+ if (entry.getKey().equalsIgnoreCase("Content-Type")) {
+ mediaType = MediaType.parse(entry.getValue());
+ } else {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ RequestBody body = request.getBody() != null ? RequestBody.create(request.getBody(), mediaType) : null;
+ requestBuilder.method(requestMethod, body);
+
+ try {
+ Response response = client.newCall(requestBuilder.build()).execute();
+ return OAuthClientResponseFactory.createCustomResponse(
+ response.body().string(),
+ response.body().contentType().toString(),
+ response.code(),
+ responseClass);
+ } catch (IOException e) {
+ throw new OAuthSystemException(e);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ // Nothing to do here
+ }
+}
+{{/hasOAuthMethods}}
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/RetryingOAuth.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/RetryingOAuth.mustache
new file mode 100644
index 00000000000..137e266b5a2
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson-nextgen/auth/RetryingOAuth.mustache
@@ -0,0 +1,184 @@
+{{#hasOAuthMethods}}
+package {{invokerPackage}}.auth;
+
+import {{invokerPackage}}.ApiException;
+import {{invokerPackage}}.Pair;
+
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import org.apache.oltu.oauth2.client.OAuthClient;
+import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
+import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
+import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
+import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.util.Map;
+import java.util.List;
+
+public class RetryingOAuth extends OAuth implements Interceptor {
+ private OAuthClient oAuthClient;
+
+ private TokenRequestBuilder tokenRequestBuilder;
+
+ public RetryingOAuth(OkHttpClient client, TokenRequestBuilder tokenRequestBuilder) {
+ this.oAuthClient = new OAuthClient(new OAuthOkHttpClient(client));
+ this.tokenRequestBuilder = tokenRequestBuilder;
+ }
+
+ public RetryingOAuth(TokenRequestBuilder tokenRequestBuilder) {
+ this(new OkHttpClient(), tokenRequestBuilder);
+ }
+
+ /**
+ @param tokenUrl The token URL to be used for this OAuth2 flow.
+ Applicable to the following OAuth2 flows: "password", "clientCredentials" and "authorizationCode".
+ The value must be an absolute URL.
+ @param clientId The OAuth2 client ID for the "clientCredentials" flow.
+ @param clientSecret The OAuth2 client secret for the "clientCredentials" flow.
+ */
+ public RetryingOAuth(
+ String tokenUrl,
+ String clientId,
+ OAuthFlow flow,
+ String clientSecret,
+ Map parameters
+ ) {
+ this(OAuthClientRequest.tokenLocation(tokenUrl)
+ .setClientId(clientId)
+ .setClientSecret(clientSecret));
+ setFlow(flow);
+ if (parameters != null) {
+ for (String paramName : parameters.keySet()) {
+ tokenRequestBuilder.setParameter(paramName, parameters.get(paramName));
+ }
+ }
+ }
+
+ public void setFlow(OAuthFlow flow) {
+ switch(flow) {
+ case accessCode:
+ tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE);
+ break;
+ case implicit:
+ tokenRequestBuilder.setGrantType(GrantType.IMPLICIT);
+ break;
+ case password:
+ tokenRequestBuilder.setGrantType(GrantType.PASSWORD);
+ break;
+ case application:
+ tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS);
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ return retryingIntercept(chain, true);
+ }
+
+ private Response retryingIntercept(Chain chain, boolean updateTokenAndRetryOnAuthorizationFailure) throws IOException {
+ Request request = chain.request();
+
+ // If the request already has an authorization (e.g. Basic auth), proceed with the request as is
+ if (request.header("Authorization") != null) {
+ return chain.proceed(request);
+ }
+
+ // Get the token if it has not yet been acquired
+ if (getAccessToken() == null) {
+ updateAccessToken(null);
+ }
+
+ OAuthClientRequest oAuthRequest;
+ if (getAccessToken() != null) {
+ // Build the request
+ Request.Builder requestBuilder = request.newBuilder();
+
+ String requestAccessToken = getAccessToken();
+ try {
+ oAuthRequest =
+ new OAuthBearerClientRequest(request.url().toString()).
+ setAccessToken(requestAccessToken).
+ buildHeaderMessage();
+ } catch (OAuthSystemException e) {
+ throw new IOException(e);
+ }
+
+ Map headers = oAuthRequest.getHeaders();
+ for (String headerName : headers.keySet()) {
+ requestBuilder.addHeader(headerName, headers.get(headerName));
+ }
+ requestBuilder.url(oAuthRequest.getLocationUri());
+
+ // Execute the request
+ Response response = chain.proceed(requestBuilder.build());
+
+ // 401/403 response codes most likely indicate an expired access token, unless it happens two times in a row
+ if (
+ response != null &&
+ ( response.code() == HttpURLConnection.HTTP_UNAUTHORIZED ||
+ response.code() == HttpURLConnection.HTTP_FORBIDDEN ) &&
+ updateTokenAndRetryOnAuthorizationFailure
+ ) {
+ try {
+ if (updateAccessToken(requestAccessToken)) {
+ response.body().close();
+ return retryingIntercept(chain, false);
+ }
+ } catch (Exception e) {
+ response.body().close();
+ throw e;
+ }
+ }
+ return response;
+ }
+ else {
+ return chain.proceed(chain.request());
+ }
+ }
+
+ /*
+ * Returns true if the access token has been updated
+ */
+ public synchronized boolean updateAccessToken(String requestAccessToken) throws IOException {
+ if (getAccessToken() == null || getAccessToken().equals(requestAccessToken)) {
+ try {
+ OAuthJSONAccessTokenResponse accessTokenResponse =
+ oAuthClient.accessToken(tokenRequestBuilder.buildBodyMessage());
+ if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
+ setAccessToken(accessTokenResponse.getAccessToken());
+ }
+ } catch (OAuthSystemException | OAuthProblemException e) {
+ throw new IOException(e);
+ }
+ }
+ return getAccessToken() == null || !getAccessToken().equals(requestAccessToken);
+ }
+
+ public TokenRequestBuilder getTokenRequestBuilder() {
+ return tokenRequestBuilder;
+ }
+
+ public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) {
+ this.tokenRequestBuilder = tokenRequestBuilder;
+ }
+
+ // Applying authorization to parameters is performed in the retryingIntercept method
+ @Override
+ public void applyToParams(List queryParams, Map headerParams, Map