Compare commits

..

2 Commits

1651 changed files with 6081 additions and 137574 deletions

View File

@@ -19,7 +19,6 @@ jobs:
with:
java-version: 11
distribution: 'temurin'
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -37,7 +37,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 11
cache: gradle
# Cache Gradle Dependencies
- name: Setup Gradle Dependencies Cache
uses: actions/cache@v4

View File

@@ -27,7 +27,6 @@ jobs:
with:
distribution: 'temurin'
java-version: ${{ matrix.java }}
cache: gradle
- uses: actions/cache@v4
with:
@@ -96,7 +95,6 @@ jobs:
with:
java-version: 11
maven-version: 3.8.8
cache: gradle
- name: Download build artifact
uses: actions/download-artifact@v5
with:

View File

@@ -21,7 +21,6 @@ jobs:
with:
java-version: 11
distribution: 'temurin'
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:
@@ -60,7 +59,6 @@ jobs:
with:
java-version: 11
distribution: 'temurin'
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -26,7 +26,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 8
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -118,7 +118,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 11
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -42,7 +42,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 17
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -20,7 +20,10 @@ jobs:
- samples/server/petstore/jaxrs/jersey2-useTags
- samples/server/petstore/jaxrs-jersey
- samples/server/petstore/jaxrs-spec
- samples/server/petstore/jaxrs-spec-withxml
- samples/server/petstore/jaxrs-spec-interface
- samples/server/petstore/jaxrs-spec-interface-response
- samples/server/petstore/jaxrs-jersey
- samples/server/petstore/jaxrs-spec
- samples/server/petstore/jaxrs-spec-interface
- samples/server/petstore/jaxrs-spec-interface-response
- samples/server/petstore/jaxrs-datelib-j8

View File

@@ -77,7 +77,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 11
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -26,7 +26,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 17
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -52,7 +52,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 17
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -32,7 +32,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 21
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -59,8 +59,7 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 11
cache: gradle
java-version: 8
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

@@ -1,142 +0,0 @@
name: Samples TS clients
on:
push:
paths:
- samples/client/others/typescript-angular/**
# comment out angular released before Nov 2023
#- samples/client/petstore/typescript-angular-v12-provided-in-root/**
#- samples/client/petstore/typescript-angular-v13-provided-in-root/**
#- samples/client/petstore/typescript-angular-v14-provided-in-root/**
#- samples/client/petstore/typescript-angular-v15-provided-in-root/**
- samples/client/petstore/typescript-angular-v16-provided-in-root/**
- samples/client/petstore/typescript-angular-v17-provided-in-root/**
- samples/client/petstore/typescript-angular-v18-provided-in-root/**
- samples/client/petstore/typescript-angular-v19-provided-in-root/**
- samples/client/petstore/typescript-angular-v20-provided-in-root/**
- samples/openapi3/client/petstore/typescript/builds/default/**
# comment out due to build failure
#- samples/openapi3/client/petstore/typescript/tests/default/**
- samples/openapi3/client/petstore/typescript/builds/jquery/**
# comment out due to build failure
#- samples/openapi3/client/petstore/typescript/tests/jquery/**
- samples/openapi3/client/petstore/typescript/builds/object_params/**
# comment out due to build failure
#- samples/openapi3/client/petstore/typescript/tests/object_params/**
#- samples/openapi3/client/petstore/typescript/builds/inversify/**
#- samples/openapi3/client/petstore/typescript/tests/inversify/**
#- samples/openapi3/client/petstore/typescript/tests/deno/**
- samples/openapi3/client/petstore/typescript/builds/browser/**
# comment out due to build failure
#- samples/openapi3/client/petstore/typescript/tests/browser/**
#- samples/openapi3/client/petstore/typescript/builds/nullable-enum/**
- samples/client/petstore/typescript-fetch/builds/default/**
- samples/client/petstore/typescript-fetch/builds/es6-target/**
- samples/client/petstore/typescript-fetch/builds/with-npm-version/**
- samples/client/petstore/typescript-fetch/tests/default/**
# comment out due to build failure
#- samples/client/petstore/typescript-node/npm/**
- samples/client/petstore/typescript-rxjs/builds/with-npm-version/**
- samples/client/petstore/typescript-axios/builds/with-npm-version/**
# comment out due to build failure
#- samples/client/petstore/typescript-axios/tests/default/**
pull_request:
paths:
- samples/client/others/typescript-angular/**
#- samples/client/petstore/typescript-angular-v12-provided-in-root/**
#- samples/client/petstore/typescript-angular-v13-provided-in-root/**
#- samples/client/petstore/typescript-angular-v14-provided-in-root/**
#- samples/client/petstore/typescript-angular-v15-provided-in-root/**
- samples/client/petstore/typescript-angular-v16-provided-in-root/**
- samples/client/petstore/typescript-angular-v17-provided-in-root/**
- samples/client/petstore/typescript-angular-v18-provided-in-root/**
- samples/client/petstore/typescript-angular-v19-provided-in-root/**
- samples/client/petstore/typescript-angular-v20-provided-in-root/**
- samples/openapi3/client/petstore/typescript/builds/default/**
#- samples/openapi3/client/petstore/typescript/tests/default/**
- samples/openapi3/client/petstore/typescript/builds/jquery/**
#- samples/openapi3/client/petstore/typescript/tests/jquery/**
- samples/openapi3/client/petstore/typescript/builds/object_params/**
#- samples/openapi3/client/petstore/typescript/tests/object_params/**
#- samples/openapi3/client/petstore/typescript/builds/inversify/**
#- samples/openapi3/client/petstore/typescript/tests/inversify/**
#- samples/openapi3/client/petstore/typescript/tests/deno/**
- samples/openapi3/client/petstore/typescript/builds/browser/**
#- samples/openapi3/client/petstore/typescript/tests/browser/**
#- samples/openapi3/client/petstore/typescript/builds/nullable-enum/**
- samples/client/petstore/typescript-fetch/builds/default/**
- samples/client/petstore/typescript-fetch/builds/es6-target/**
- samples/client/petstore/typescript-fetch/builds/with-npm-version/**
- samples/client/petstore/typescript-fetch/tests/default/**
#- samples/client/petstore/typescript-node/npm/**
- samples/client/petstore/typescript-rxjs/builds/with-npm-version/**
- samples/client/petstore/typescript-axios/builds/with-npm-version/**
#- samples/client/petstore/typescript-axios/tests/default/**
jobs:
build:
name: Build projects
runs-on: ubuntu-latest
services:
petstore-api:
image: swaggerapi/petstore
ports:
- 80:8080
env:
SWAGGER_HOST: http://petstore.swagger.io
SWAGGER_BASE_PATH: /v2
strategy:
fail-fast: false
matrix:
node:
#- "18.x"
- "20.x"
sample:
- samples/client/others/typescript-angular/
#- samples/client/petstore/typescript-angular-v12-provided-in-root/
#- samples/client/petstore/typescript-angular-v13-provided-in-root/
#- samples/client/petstore/typescript-angular-v14-provided-in-root/
#- samples/client/petstore/typescript-angular-v15-provided-in-root/
- samples/client/petstore/typescript-angular-v16-provided-in-root/
- samples/client/petstore/typescript-angular-v17-provided-in-root/
- samples/client/petstore/typescript-angular-v18-provided-in-root/
- samples/client/petstore/typescript-angular-v19-provided-in-root/
- samples/client/petstore/typescript-angular-v20-provided-in-root/
- samples/openapi3/client/petstore/typescript/builds/default/
#- samples/openapi3/client/petstore/typescript/tests/default/
- samples/openapi3/client/petstore/typescript/builds/jquery/
#- samples/openapi3/client/petstore/typescript/tests/jquery/
- samples/openapi3/client/petstore/typescript/builds/object_params/
#- samples/openapi3/client/petstore/typescript/tests/object_params/
#- samples/openapi3/client/petstore/typescript/builds/inversify/
#- samples/openapi3/client/petstore/typescript/tests/inversify/
#- samples/openapi3/client/petstore/typescript/tests/deno/
- samples/openapi3/client/petstore/typescript/builds/browser/
#- samples/openapi3/client/petstore/typescript/tests/browser/
#- samples/openapi3/client/petstore/typescript/builds/nullable-enum/
- samples/client/petstore/typescript-fetch/builds/default/
- samples/client/petstore/typescript-fetch/builds/es6-target/
- samples/client/petstore/typescript-fetch/builds/with-npm-version/
- samples/client/petstore/typescript-fetch/tests/default/
#- samples/client/petstore/typescript-node/npm/
- samples/client/petstore/typescript-rxjs/builds/with-npm-version/
- samples/client/petstore/typescript-axios/builds/with-npm-version/
#- samples/client/petstore/typescript-axios/tests/default/
steps:
- uses: actions/checkout@v5
- name: Add hosts to /etc/hosts
run: |
sudo echo "127.0.0.1 petstore.swagger.io" | sudo tee -a /etc/hosts
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: '17' # Specify your desired Java version
distribution: 'temurin' # Or 'adopt', 'oracle', etc.
cache: maven # Cache Maven dependencies for faster builds
- name: Use Node.js
uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node }}
cache: 'npm' # Or 'yarn'
- name: mvn integration-test
working-directory: ${{ matrix.sample }}
run: mvn integration-test

View File

@@ -24,7 +24,6 @@ jobs:
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

2
.gitignore vendored
View File

@@ -49,8 +49,6 @@ nb-configuration.xml
*.xml~
*.t~
**/.angular
/target
/generated-files
test-output/

View File

@@ -11,15 +11,43 @@ export NODE_ENV=test
if [ "$NODE_INDEX" = "1" ]; then
echo "Running node $NODE_INDEX ..."
java -version
sudo apt-get -y install cpanminus
# install rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
echo "Testing perl"
(cd samples/client/petstore/perl && /bin/bash ./test.bash)
echo "Testing ruby"
(cd samples/client/petstore/ruby && mvn integration-test)
(cd samples/client/petstore/ruby-faraday && mvn integration-test)
(cd samples/client/petstore/ruby-httpx && mvn integration-test)
(cd samples/client/petstore/ruby-autoload && mvn integration-test)
echo "Testing rust"
(cd samples/server/petstore/rust-axum && mvn integration-test)
elif [ "$NODE_INDEX" = "2" ]; then
echo "Running node $NODE_INDEX to test cpp-restsdk"
echo "Running node $NODE_INDEX to test Go"
# install haskell
#curl -sSLk https://get.haskellstack.org/ | sh
#stack upgrade
#stack --version
# install curl
#sudo apt-get -y build-dep libcurl4-gnutls-dev
#sudo apt-get -y install libcurl4-gnutls-dev
# Install golang version 1.18
go version
sudo mkdir /usr/local/go1.18
wget -c https://dl.google.com/go/go1.18.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local/go1.18
export PATH="/usr/local/go1.18/go/bin:$PATH"
go version
# install cpprestsdk
sudo apt-get install libcpprest-dev
@@ -34,15 +62,54 @@ elif [ "$NODE_INDEX" = "3" ]; then
echo "Running node $NODE_INDEX ... "
echo "Testing ruby"
(cd samples/client/petstore/ruby && mvn integration-test)
(cd samples/client/petstore/ruby-faraday && mvn integration-test)
(cd samples/client/petstore/ruby-httpx && mvn integration-test)
(cd samples/client/petstore/ruby-autoload && mvn integration-test)
# Install node@stable (for angular 6)
set +e
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
export NVM_DIR="/opt/circleci/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
#nvm install stable
# install v16 instead of the latest stable version
nvm install 18
nvm alias default 18
node --version
# Each step uses the same `$BASH_ENV`, so need to modify it
echo 'export NVM_DIR="/opt/circleci/.nvm"' >> $BASH_ENV
echo "[ -s \"$NVM_DIR/nvm.sh\" ] && . \"$NVM_DIR/nvm.sh\"" >> $BASH_ENV
(cd samples/client/others/typescript-angular && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v12-provided-in-root && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v13-provided-in-root && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v14-provided-in-root && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v15-provided-in-root && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v16-provided-in-root && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v17-provided-in-root && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v18-provided-in-root && mvn integration-test)
(cd samples/client/petstore/typescript-angular-v19-provided-in-root && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/builds/default && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/tests/default && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/builds/jquery && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/tests/jquery && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/builds/object_params && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/tests/object_params && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/builds/inversify && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/tests/inversify && mvn integration-test)
#(cd samples/openapi3/client/petstore/typescript/tests/deno && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/builds/browser && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/tests/browser && mvn integration-test)
(cd samples/openapi3/client/petstore/typescript/builds/nullable-enum && mvn integration-test)
(cd samples/client/petstore/typescript-fetch/builds/default && mvn integration-test)
(cd samples/client/petstore/typescript-fetch/builds/es6-target && mvn integration-test)
(cd samples/client/petstore/typescript-fetch/builds/with-npm-version && mvn integration-test)
(cd samples/client/petstore/typescript-fetch/tests/default && mvn integration-test)
(cd samples/client/petstore/typescript-node/npm && mvn integration-test)
(cd samples/client/petstore/typescript-rxjs/builds/with-npm-version && mvn integration-test)
(cd samples/client/petstore/typescript-axios/builds/with-npm-version && mvn integration-test)
(cd samples/client/petstore/typescript-axios/tests/default && mvn integration-test)
(cd samples/client/petstore/typescript-axios/tests/with-complex-headers && mvn integration-test)
else
echo "Running node $NODE_INDEX ..."
java -version
./mvnw clean install
fi

View File

@@ -1,10 +0,0 @@
generatorName: jaxrs-spec
outputDir: samples/server/petstore/jaxrs-spec-withxml/
inputSpec: modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec
additionalProperties:
artifactId: jaxrs-spec-withxml-petstore-server
serializableModel: "true"
hideGenerationTimestamp: "true"
generateBuilders: "true"
withXml: true

View File

@@ -1,9 +0,0 @@
generatorName: typescript-angular
outputDir: samples/client/petstore/typescript-angular-v19-provided-in-root/builds/default
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
additionalProperties:
ngVersion: 19.0.0
supportsES6: true
enumNameMappings:
delivered: SHIPPED

View File

@@ -1,9 +0,0 @@
generatorName: typescript-angular
outputDir: samples/client/petstore/typescript-angular-v20-provided-in-root/builds/default
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
additionalProperties:
ngVersion: 20.0.0
supportsES6: true
enumNameMappings:
delivered: SHIPPED

View File

@@ -1,7 +0,0 @@
generatorName: typescript-fetch
outputDir: samples/client/others/typescript-fetch/infinite-recursion-issue
inputSpec: modules/openapi-generator/src/test/resources/3_0/typescript-fetch/infinite-recursion-issue.yaml
templateDir: modules/openapi-generator/src/main/resources/typescript-fetch
additionalProperties:
enumPropertyNaming: "original"
enumUnknownDefaultCase: true

View File

@@ -538,7 +538,6 @@ OpenAPI Normalizer transforms the input OpenAPI doc/spec (which may not perfectl
- SIMPLIFY_ONEOF_ANYOF
- SIMPLIFY_BOOLEAN_ENUM
- REFACTOR_ALLOF_WITH_PROPERTIES_ONLY
(One can use `DISABLE_ALL=true` to disable all the rules)
@@ -646,7 +645,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat
- `FILTER`
The `FILTER` parameter allows selective inclusion of API operations based on specific criteria. It applies the `x-internal: true` property to operations that do **not** match the specified values, preventing them from being generated. Multiple filters can be separated by a semicolon.
The `FILTER` parameter allows selective inclusion of API operations based on specific criteria. It applies the `x-internal: true` property to operations that do **not** match the specified values, preventing them from being generated.
### Available Filters
@@ -659,9 +658,6 @@ The `FILTER` parameter allows selective inclusion of API operations based on spe
- **`tag`**
When set to `tag:person|basic`, operations **not** tagged with `person` or `basic` will be marked as internal (`x-internal: true`), and will not be generated.
- **`path`**
When set to `path:/v1|/v2`, operations on paths **not** starting with `/v1` or with `/v2` will be marked as internal (`x-internal: true`), and will not be generated.
### Example Usage
```sh
@@ -669,7 +665,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat
-g java \
-i modules/openapi-generator/src/test/resources/3_0/petstore.yaml \
-o /tmp/java-okhttp/ \
--openapi-normalizer FILTER="operationId:addPet|getPetById ; tag:store"
--openapi-normalizer FILTER="operationId:addPet|getPetById"
```
- `SET_CONTAINER_TO_NULLABLE`: When set to `array|set|map` (or just `array`) for example, it will set `nullable` in array, set and map to true.

View File

@@ -3,7 +3,6 @@ id: generators
title: Generators List
---
[main] INFO o.o.c.l.PythonFastAPIServerCodegen - Skipping sorting of path operations, order matters, let the developer decide via their specification file.
The following generators are available:
## CLIENT generators

View File

@@ -133,9 +133,6 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|x-spring-paginated|Add `org.springframework.data.domain.Pageable` to controller method. Can be used to handle `page`, `size` and `sort` query parameters. If these query parameters are also specified in the operation spec, they will be removed from the controller method as their values can be obtained from the `Pageable` object.|OPERATION|false
|x-version-param|Marker property that tells that this parameter would be used for endpoint versioning. Applicable for headers & query params. true/false|OPERATION_PARAMETER|null
|x-pattern-message|Add this property whenever you need to customize the invalidation error message for the regex pattern of a variable|FIELD, OPERATION_PARAMETER|null
|x-size-message|Add this property whenever you need to customize the invalidation error message for the size or length of a variable|FIELD, OPERATION_PARAMETER|null
|x-minimum-message|Add this property whenever you need to customize the invalidation error message for the minimum value of a variable|FIELD, OPERATION_PARAMETER|null
|x-maximum-message|Add this property whenever you need to customize the invalidation error message for the maximum value of a variable|FIELD, OPERATION_PARAMETER|null
|x-spring-api-version|Value for 'version' attribute in @RequestMapping (for Spring 7 and above).|OPERATION|null

View File

@@ -67,9 +67,6 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|x-discriminator-value|Used with model inheritance to specify value for discriminator that identifies current model|MODEL|
|x-field-extra-annotation|List of custom annotations to be added to property|FIELD, OPERATION_PARAMETER|null
|x-pattern-message|Add this property whenever you need to customize the invalidation error message for the regex pattern of a variable|FIELD, OPERATION_PARAMETER|null
|x-size-message|Add this property whenever you need to customize the invalidation error message for the size or length of a variable|FIELD, OPERATION_PARAMETER|null
|x-minimum-message|Add this property whenever you need to customize the invalidation error message for the minimum value of a variable|FIELD, OPERATION_PARAMETER|null
|x-maximum-message|Add this property whenever you need to customize the invalidation error message for the maximum value of a variable|FIELD, OPERATION_PARAMETER|null
|x-kotlin-implements|Ability to specify interfaces that model must implement|MODEL|empty array
|x-kotlin-implements-fields|Specify attributes that are implemented by the interface(s) added via `x-kotlin-implements`|MODEL|empty array

View File

@@ -126,9 +126,6 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|x-spring-paginated|Add `org.springframework.data.domain.Pageable` to controller method. Can be used to handle `page`, `size` and `sort` query parameters. If these query parameters are also specified in the operation spec, they will be removed from the controller method as their values can be obtained from the `Pageable` object.|OPERATION|false
|x-version-param|Marker property that tells that this parameter would be used for endpoint versioning. Applicable for headers & query params. true/false|OPERATION_PARAMETER|null
|x-pattern-message|Add this property whenever you need to customize the invalidation error message for the regex pattern of a variable|FIELD, OPERATION_PARAMETER|null
|x-size-message|Add this property whenever you need to customize the invalidation error message for the size or length of a variable|FIELD, OPERATION_PARAMETER|null
|x-minimum-message|Add this property whenever you need to customize the invalidation error message for the minimum value of a variable|FIELD, OPERATION_PARAMETER|null
|x-maximum-message|Add this property whenever you need to customize the invalidation error message for the maximum value of a variable|FIELD, OPERATION_PARAMETER|null
|x-spring-api-version|Value for 'version' attribute in @RequestMapping (for Spring 7 and above).|OPERATION|null

View File

@@ -44,7 +44,6 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|supportsES6|Generate code that conforms to ES6.| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.| |false|
|useSquareBracketsInArrayNames|Setting this property to true will add brackets to array attribute names, e.g. my_values[].| |false|
|withAWSV4Signature|whether to include AWS v4 signature support| |false|
|withInterfaces|Setting this property to true will generate interfaces next to the default class implementations.| |false|
|withNodeImports|Setting this property to true adds imports for NodeJS| |false|
|withSeparateModelsAndApi|Put the model and api in separate folders and in separate classes. This requires in addition a value for 'apiPackage' and 'modelPackage'| |false|
@@ -292,7 +291,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|OAuth2_ClientCredentials|✗|OAS2,OAS3
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
|SignatureAuth|✗|OAS3
|AWSV4Signature||ToolingExtension
|AWSV4Signature||ToolingExtension
### Wire Format Feature
| Name | Supported | Defined By |

View File

@@ -29,7 +29,6 @@ import io.airlift.airline.Arguments;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.Strings;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.CodegenConfig;
@@ -249,7 +248,7 @@ public class GenerateBatch extends OpenApiGeneratorCommand {
Path filesMeta = Paths.get(outDir.toAbsolutePath().toString(), ".openapi-generator", "FILES");
if (filesMeta.toFile().exists()) {
FileUtils.readLines(filesMeta.toFile(), StandardCharsets.UTF_8).forEach(relativePath -> {
if (!Strings.CS.startsWith(relativePath, ".")) {
if (!StringUtils.startsWith(relativePath, ".")) {
Path file = outDir.resolve(relativePath).toAbsolutePath();
// hack: disallow directory traversal outside of output directory. we don't want to delete wrong files.
if (file.toString().startsWith(outDir.toAbsolutePath().toString())) {

View File

@@ -5734,7 +5734,7 @@ public class DefaultCodegen implements CodegenConfig {
cs.name = key;
cs.description = securityScheme.getDescription();
cs.type = securityScheme.getType().toString();
cs.isCode = cs.isPassword = cs.isApplication = cs.isImplicit = cs.isOpenId = cs.isOAuth = false;
cs.isCode = cs.isPassword = cs.isApplication = cs.isImplicit = cs.isOpenId = false;
cs.isHttpSignature = false;
cs.isBasicBasic = cs.isBasicBearer = false;
cs.scheme = securityScheme.getScheme();

View File

@@ -353,22 +353,18 @@ public class InlineModelResolver {
}
}
}
} else {
if (schema.getProperties() != null) {
// If non-object type is specified but also properties
LOGGER.warn("Illegal schema found with non-object type ({}) combined with properties. Properties automatically removed.", schema.getType());
schema.setProperties(null);
return;
}
if (schema.getAdditionalProperties() != null) {
// If non-object type is specified but also additionalProperties
LOGGER.error("Illegal schema found with non-object type ({}) combined with additionalProperties. AdditionalProperties automatically removed.", schema.getType());
schema.setAdditionalProperties(null);
return;
}
} else if (schema.getProperties() != null) {
// If non-object type is specified but also properties
LOGGER.error("Illegal schema found with non-object type combined with properties," +
" no properties should be defined:\n " + schema.toString());
return;
} else if (schema.getAdditionalProperties() != null) {
// If non-object type is specified but also additionalProperties
LOGGER.error("Illegal schema found with non-object type combined with" +
" additionalProperties, no additionalProperties should be defined:\n " +
schema.toString());
return;
}
// Check array items
if (ModelUtils.isArraySchema(schema)) {
Schema items = ModelUtils.getSchemaItems(schema);

View File

@@ -49,7 +49,7 @@ public class OpenAPINormalizer {
private TreeSet<String> anyTypeTreeSet = new TreeSet<>();
protected static final Logger LOGGER = LoggerFactory.getLogger(OpenAPINormalizer.class);
protected final Logger LOGGER = LoggerFactory.getLogger(OpenAPINormalizer.class);
Set<String> ruleNames = new TreeSet<>();
Set<String> rulesDefaultToTrue = new TreeSet<>();
@@ -133,6 +133,10 @@ public class OpenAPINormalizer {
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
final String FILTER = "FILTER";
HashSet<String> operationIdFilters = new HashSet<>();
HashSet<String> methodFilters = new HashSet<>();
HashSet<String> tagFilters = new HashSet<>();
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
final String SET_CONTAINER_TO_NULLABLE = "SET_CONTAINER_TO_NULLABLE";
@@ -211,7 +215,6 @@ public class OpenAPINormalizer {
rules.put(SIMPLIFY_ONEOF_ANYOF, true);
rules.put(SIMPLIFY_BOOLEAN_ENUM, true);
rules.put(SIMPLIFY_ONEOF_ANYOF_ENUM, true);
rules.put(REFACTOR_ALLOF_WITH_PROPERTIES_ONLY, true);
processRules(inputRules);
@@ -272,7 +275,30 @@ public class OpenAPINormalizer {
if (inputRules.get(FILTER) != null) {
rules.put(FILTER, true);
// actual parsing is delayed to allow customization of the Filter processing
String[] filterStrs = inputRules.get(FILTER).split(":");
if (filterStrs.length != 2) { // only support operationId with : at the moment
LOGGER.error("FILTER rule must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3`: {}", inputRules.get(FILTER));
} else {
if ("operationId".equals(filterStrs[0])) {
operationIdFilters = Arrays.stream(filterStrs[1].split("[|]"))
.filter(Objects::nonNull)
.map(String::trim)
.collect(Collectors.toCollection(HashSet::new));
} else if ("method".equals(filterStrs[0])) {
methodFilters = Arrays.stream(filterStrs[1].split("[|]"))
.filter(Objects::nonNull)
.map(String::trim)
.collect(Collectors.toCollection(HashSet::new));
} else if ("tag".equals(filterStrs[0])) {
tagFilters = Arrays.stream(filterStrs[1].split("[|]"))
.filter(Objects::nonNull)
.map(String::trim)
.collect(Collectors.toCollection(HashSet::new));
} else {
LOGGER.error("FILTER rule must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3`: {}", inputRules.get(FILTER));
}
}
}
if (inputRules.get(SET_CONTAINER_TO_NULLABLE) != null) {
@@ -318,19 +344,6 @@ public class OpenAPINormalizer {
}
}
/**
* Create the filter to process the FILTER normalizer.
* Override this to create a custom filter normalizer.
*
* @param openApi Contract used in the filtering (could be used for customization).
* @param filters full FILTER value
*
* @return a Filter containing the parsed filters.
*/
protected Filter createFilter(OpenAPI openApi, String filters) {
return new Filter(filters);
}
/**
* Normalizes the OpenAPI input, which may not perfectly conform to
* the specification.
@@ -392,15 +405,15 @@ public class OpenAPINormalizer {
"trace", PathItem::getTrace
);
if (Boolean.TRUE.equals(getRule(FILTER))) {
String filters = inputRules.get(FILTER);
Filter filter = createFilter(this.openAPI, filters);
if (filter.parse()) {
// Iterates over each HTTP method in methodMap, retrieves the corresponding Operations from the PathItem,
// and marks it as internal (`x-internal=true`) if the method/operationId/tag/path is not in the filters.
filter.apply(pathsEntry.getKey(), path, methodMap);
// Iterates over each HTTP method in methodMap, retrieves the corresponding Operation from the PathItem,
// and marks it as internal (`x-internal`) if the method is not in methodFilters.
methodMap.forEach((method, getter) -> {
Operation operation = getter.apply(path);
if (operation != null && !methodFilters.isEmpty()) {
LOGGER.info("operation `{}` marked internal only (x-internal: `{}`) by the method FILTER", operation.getOperationId(), !methodFilters.contains(method));
operation.addExtension("x-internal", !methodFilters.contains(method));
}
}
});
// Include callback operation as well
for (Operation operation : path.readOperations()) {
@@ -417,6 +430,22 @@ public class OpenAPINormalizer {
normalizeParameters(path.getParameters());
for (Operation operation : operations) {
if (operationIdFilters.size() > 0) {
if (operationIdFilters.contains(operation.getOperationId())) {
operation.addExtension(X_INTERNAL, false);
} else {
LOGGER.info("operation `{}` marked as internal only (x-internal: true) by the operationId FILTER", operation.getOperationId());
operation.addExtension(X_INTERNAL, true);
}
} else if (!tagFilters.isEmpty()) {
if (operation.getTags().stream().anyMatch(tagFilters::contains)) {
operation.addExtension(X_INTERNAL, false);
} else {
LOGGER.info("operation `{}` marked as internal only (x-internal: true) by the tag FILTER", operation.getOperationId());
operation.addExtension(X_INTERNAL, true);
}
}
normalizeOperation(operation);
normalizeRequestBody(operation);
normalizeParameters(operation.getParameters());
@@ -1334,7 +1363,7 @@ public class OpenAPINormalizer {
*
* @param schema Schema to modify
* @param subSchemas List of sub-schemas to check
* @param composedType Type of composed schema ("oneOf" or "anyOf")
* @param schemaType Type of composed schema ("oneOf" or "anyOf")
* @return Simplified schema
*/
protected Schema simplifyComposedSchemaWithEnums(Schema schema, List<Object> subSchemas, String composedType) {
@@ -1803,164 +1832,4 @@ public class OpenAPINormalizer {
}
// ===================== end of rules =====================
protected static class Filter {
public static final String OPERATION_ID = "operationId";
public static final String METHOD = "method";
public static final String TAG = "tag";
public static final String PATH = "path";
private final String filters;
protected Set<String> operationIdFilters = Collections.emptySet();
protected Set<String> methodFilters = Collections.emptySet();
protected Set<String> tagFilters = Collections.emptySet();
protected Set<String> pathStartingWithFilters = Collections.emptySet();
private boolean hasFilter;
protected Filter(String filters) {
this.filters = filters.trim();
}
/**
* Perform the parsing of the filter string.
*
* @return true if filters need to be processed
*/
public boolean parse() {
if (StringUtils.isEmpty(filters)) {
return false;
}
try {
doParse();
return hasFilter();
} catch (RuntimeException e) {
String message = String.format(Locale.ROOT, "FILTER rule [%s] must be in the form of `%s:name1|name2|name3` or `%s:get|post|put` or `%s:tag1|tag2|tag3` or `%s:/v1|/v2`. Error: %s",
filters, Filter.OPERATION_ID, Filter.METHOD, Filter.TAG, Filter.PATH, e.getMessage());
// throw an exception. This is a breaking change compared to pre 7.16.0
// Workaround: fix the syntax!
throw new IllegalArgumentException(message);
}
}
private void doParse() {
for (String filter : filters.split(";")) {
filter = filter.trim();
String[] filterStrs = filter.split(":");
if (filterStrs.length != 2) { // only support filter with : at the moment
throw new IllegalArgumentException("filter with no value not supported :[" + filter + "]");
} else {
String filterKey = filterStrs[0].trim();
String filterValue = filterStrs[1];
Set<String> parsedFilters = splitByPipe(filterValue);
hasFilter = true;
if (OPERATION_ID.equals(filterKey)) {
operationIdFilters = parsedFilters;
} else if (METHOD.equals(filterKey)) {
methodFilters = parsedFilters;
} else if (TAG.equals(filterKey)) {
tagFilters = parsedFilters;
} else if (PATH.equals(filterKey)) {
pathStartingWithFilters = parsedFilters;
} else {
parse(filterKey, filterValue);
}
}
}
}
/**
* Split the filterValue by pipe.
*
* @return the split values.
*/
protected Set<String> splitByPipe(String filterValue) {
return Arrays.stream(filterValue.split("[|]"))
.filter(Objects::nonNull)
.map(String::trim)
.collect(Collectors.toCollection(HashSet::new));
}
/**
* Parse non default filters.
*
* Override this method to add custom parsing logic.
*
* By default throws IllegalArgumentException.
*
* @param filterName name of the filter
* @param filterValue value of the filter
*/
protected void parse(String filterName, String filterValue) {
parseFails(filterName, filterValue);
}
protected void parseFails(String filterName, String filterValue) {
throw new IllegalArgumentException("filter not supported :[" + filterName + ":" + filterValue + "]");
}
/**
* Test if the OpenAPI contract match an extra filter.
*
* Override this method to add custom logic.
*
* @param operation Openapi Operation
* @param path Path of the operation
*
* @return true if the operation of path match the filter
*/
protected boolean hasCustomFilterMatch(String path, Operation operation) {
return false;
}
public boolean hasFilter() {
return hasFilter;
}
public void apply(String path, PathItem pathItem, Map<String, Function<PathItem, Operation>> methodMap) {
methodMap.forEach((method, getter) -> {
Operation operation = getter.apply(pathItem);
if (operation != null) {
boolean found = false;
found |= logIfMatch(PATH, operation, hasPathStarting(path));
found |= logIfMatch(TAG, operation, hasTag(operation));
found |= logIfMatch(OPERATION_ID, operation, hasOperationId(operation));
found |= logIfMatch(METHOD, operation, hasMethod(method));
found |= hasCustomFilterMatch(path, operation);
operation.addExtension(X_INTERNAL, !found);
}
});
}
protected boolean logIfMatch(String filterName, Operation operation, boolean filterMatched) {
if (filterMatched) {
logMatch(filterName, operation);
}
return filterMatched;
}
protected void logMatch(String filterName, Operation operation) {
getLogger().info("operation `{}` marked as internal only (x-internal: true) by the {} FILTER", operation.getOperationId(), filterName);
}
protected Logger getLogger() {
return OpenAPINormalizer.LOGGER;
}
private boolean hasPathStarting(String path) {
return pathStartingWithFilters.stream().anyMatch(filter -> path.startsWith(filter));
}
private boolean hasTag( Operation operation) {
return operation.getTags() != null && operation.getTags().stream().anyMatch(tagFilters::contains);
}
private boolean hasOperationId(Operation operation) {
return operationIdFilters.contains(operation.getOperationId());
}
private boolean hasMethod(String method) {
return methodFilters.contains(method);
}
}
}

View File

@@ -27,9 +27,6 @@ public enum VendorExtension {
X_OPERATION_EXTRA_ANNOTATION("x-operation-extra-annotation", ExtensionLevel.OPERATION, "List of custom annotations to be added to operation", null),
X_VERSION_PARAM("x-version-param", ExtensionLevel.OPERATION_PARAMETER, "Marker property that tells that this parameter would be used for endpoint versioning. Applicable for headers & query params. true/false", null),
X_PATTERN_MESSAGE("x-pattern-message", Arrays.asList(ExtensionLevel.FIELD, ExtensionLevel.OPERATION_PARAMETER), "Add this property whenever you need to customize the invalidation error message for the regex pattern of a variable", null),
X_SIZE_MESSAGE("x-size-message", Arrays.asList(ExtensionLevel.FIELD, ExtensionLevel.OPERATION_PARAMETER), "Add this property whenever you need to customize the invalidation error message for the size or length of a variable", null),
X_MINIMUM_MESSAGE("x-minimum-message", Arrays.asList(ExtensionLevel.FIELD, ExtensionLevel.OPERATION_PARAMETER), "Add this property whenever you need to customize the invalidation error message for the minimum value of a variable", null),
X_MAXIMUM_MESSAGE("x-maximum-message", Arrays.asList(ExtensionLevel.FIELD, ExtensionLevel.OPERATION_PARAMETER), "Add this property whenever you need to customize the invalidation error message for the maximum value of a variable", null),
X_ZERO_BASED_ENUM("x-zero-based-enum", ExtensionLevel.MODEL, "When used on an enum, the index will not be generated and the default numbering will be used, zero-based", "false");
private final String name;

View File

@@ -117,9 +117,6 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
// A cache to efficiently lookup schema `toModelName()` based on the schema Key
private final Map<String, String> schemaKeyToModelNameCache = new HashMap<>();
// A cache to efficiently lookup CodegenModel `fromModel(codegenModelName, parentModelSchema)` based on the pair of model name and schema
private final Map<Map.Entry<String, Schema>, CodegenModel> codegenModelNameAndSchemaKeyToCodegenModelCache = new HashMap<>();
public AbstractCSharpCodegen() {
super();
@@ -756,9 +753,13 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
return value;
}
/**
* Fixes nested maps so the generic type is defined
* Convertes List<List>> to List<List<T>>
/**
* Ensures property name is unique and not a reserved word.
* @param model
* @param property
* @param value
* @param composedPropertyNames
* @return
*/
private String patchPropertyName(CodegenModel model, CodegenProperty property, String value, Set<String> composedPropertyNames) {
value = setUniquePropertyName(model, property, value);
@@ -797,6 +798,10 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
protected void patchPropertyIsInherited(CodegenModel model, CodegenProperty property) {
}
/**
* Fixes nested maps so the generic type is defined
* Convertes List<List>> to List<List<T>>
*/
private void patchNestedMaps(CodegenProperty property) {
// Process nested types before making any replacements to ensure we have the correct inner type
if (property.items != null) {
@@ -828,6 +833,41 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
}
}
/**
* Fixes nested maps so the generic type is defined
* Convertes List<List>> to List<List<T>>
*/
private void patchNestedMaps(CodegenResponse response) {
// Process nested types before making any replacements to ensure we have the correct inner type
if (response.items != null) {
patchNestedMaps(response.items);
}
String[] nestedTypes = {"List", "Collection", "ICollection", "Dictionary"};
if (response.dataType != null) {
String originalType = response.dataType;
for (String nestedType : nestedTypes) {
// fix incorrect data types for maps of maps
if (response.items != null) {
if (response.dataType.contains(", " + nestedType + ">")) {
response.dataType = response.dataType.replace(", " + nestedType + ">", ", " + response.items.datatypeWithEnum + ">");
}
if (response.dataType.contains("<" + nestedType + ">")) {
response.dataType = response.dataType.replace("<" + nestedType + ">", "<" + response.items.datatypeWithEnum + ">");
}
}
}
// Only update dataType if we actually made changes
if (!originalType.equals(response.dataType)) {
response.dataType = response.dataType;
}
}
}
protected void patchProperty(Map<String, CodegenModel> enumRefs, CodegenModel model, CodegenProperty property) {
if (enumRefs.containsKey(property.dataType)) {
// Handle any enum properties referred to by $ref.
@@ -965,6 +1005,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
}
if (operation.responses != null) {
for (CodegenResponse response : operation.responses) {
patchNestedMaps(response);
if (response.returnProperty != null) {
Boolean isValueType = isValueType(response.returnProperty);
@@ -1628,7 +1669,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
Schema<?> target = ModelUtils.isGenerateAliasAsModel() ? p : schema;
if (ModelUtils.isArraySchema(target)) {
Schema<?> items = getSchemaItems(schema);
return typeMapping.get("array") + "<" + getTypeDeclarationForArray(items) + ">";
return getSchemaType(target) + "<" + getTypeDeclarationForArray(items) + ">";
} else if (ModelUtils.isMapSchema(p)) {
// Should we also support maps of maps?
Schema<?> inner = ModelUtils.getAdditionalProperties(p);
@@ -1707,17 +1748,6 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
return toModelName(name) + "Tests";
}
protected CodegenModel getCodegenModel(String codegenModelName, Schema schema){
var key = new AbstractMap.SimpleEntry<>(codegenModelName, schema);
if(codegenModelNameAndSchemaKeyToCodegenModelCache.containsKey(key)){
return codegenModelNameAndSchemaKeyToCodegenModelCache.get(key);
}
CodegenModel model = super.fromModel(codegenModelName, schema);
codegenModelNameAndSchemaKeyToCodegenModelCache.put(key, model);
return model;
}
public void setNullableReferenceTypes(final Boolean nullReferenceTypesFlag) {
this.nullReferenceTypesFlag = nullReferenceTypesFlag;
additionalProperties.put("nullableReferenceTypes", nullReferenceTypesFlag);

View File

@@ -34,7 +34,6 @@ import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.apache.commons.lang3.Strings;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.features.DocumentationFeature;
@@ -602,7 +601,7 @@ public abstract class AbstractPythonConnexionServerCodegen extends AbstractPytho
@Override
public String toModelImport(String name) {
String modelImport;
if (Strings.CS.startsWithAny(name, "import", "from")) {
if (StringUtils.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -437,7 +437,7 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
if (allDefinitions != null && codegenModel != null && codegenModel.parent != null) {
final Schema<?> parentModel = allDefinitions.get(toModelName(codegenModel.parent));
if (parentModel != null) {
final CodegenModel parentCodegenModel = getCodegenModel(codegenModel.parent, parentModel);
final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
if (codegenModel.hasEnums) {
codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel);
}

View File

@@ -381,7 +381,7 @@ public class CSharpReducedClientCodegen extends AbstractCSharpCodegen {
if (allDefinitions != null && codegenModel != null && codegenModel.parent != null) {
final Schema parentModel = allDefinitions.get(toModelName(codegenModel.parent));
if (parentModel != null) {
final CodegenModel parentCodegenModel = getCodegenModel(codegenModel.parent, parentModel);
final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
if (codegenModel.hasEnums) {
codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel);
}

View File

@@ -1012,9 +1012,6 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
extensions.add(VendorExtension.X_DISCRIMINATOR_VALUE);
extensions.add(VendorExtension.X_FIELD_EXTRA_ANNOTATION);
extensions.add(VendorExtension.X_PATTERN_MESSAGE);
extensions.add(VendorExtension.X_SIZE_MESSAGE);
extensions.add(VendorExtension.X_MINIMUM_MESSAGE);
extensions.add(VendorExtension.X_MAXIMUM_MESSAGE);
extensions.add(VendorExtension.X_KOTLIN_IMPLEMENTS);
extensions.add(VendorExtension.X_KOTLIN_IMPLEMENTS_FIELDS);
return extensions;

View File

@@ -20,7 +20,7 @@ package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.Setter;
import org.apache.commons.lang3.Strings;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
@@ -355,7 +355,7 @@ public class PythonClientCodegen extends AbstractPythonCodegen implements Codege
@Override
public String toModelImport(String name) {
String modelImport;
if (Strings.CS.startsWithAny(name, "import", "from")) {
if (StringUtils.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -23,7 +23,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.lang3.Strings;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.GeneratorMetadata;
@@ -90,11 +89,6 @@ public class PythonFastAPIServerCodegen extends AbstractPythonCodegen {
public PythonFastAPIServerCodegen() {
super();
// Skip sorting of operations to preserve the order found in the OpenAPI spec file. See
// https://fastapi.tiangolo.com/tutorial/path-params/?h=path#order-matters for details on why order matters.
LOGGER.info("Skipping sorting of path operations, order matters, let the developer decide via their specification file.");
setSkipSortingOperations(true);
modifyFeatureSet(features -> features.includeSecurityFeatures(
SecurityFeature.OAuth2_AuthorizationCode,
SecurityFeature.OAuth2_Password
@@ -204,7 +198,7 @@ public class PythonFastAPIServerCodegen extends AbstractPythonCodegen {
@Override
public String toModelImport(String name) {
String modelImport;
if (Strings.CS.startsWithAny(name, "import", "from")) {
if (StringUtils.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -20,7 +20,6 @@ package org.openapitools.codegen.languages;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.Setter;
import org.apache.commons.lang3.Strings;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.GeneratorMetadata;
@@ -354,7 +353,7 @@ public class PythonPydanticV1ClientCodegen extends AbstractPythonPydanticV1Codeg
@Override
public String toModelImport(String name) {
String modelImport;
if (Strings.CS.startsWithAny(name, "import", "from")) {
if (StringUtils.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -861,24 +861,6 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege
}
if (op.bodyParam != null) {
final var dataType = op.bodyParam.dataType;
if (dataType.startsWith(vecType + "<String")) {
op.bodyParam.vendorExtensions.put("is-vec-string", true);
} else if (dataType.startsWith(vecType + "<models::")) {
op.bodyParam.vendorExtensions.put("is-vec-nested", true);
} else if (dataType.startsWith(mapType + "<String, String")) {
op.bodyParam.vendorExtensions.put("is-map-string", true);
} else if (dataType.startsWith(mapType + "<String, models::")) {
op.bodyParam.vendorExtensions.put("is-map-nested", true);
} else if (dataType.startsWith(mapType + "<String")) {
op.bodyParam.vendorExtensions.put("is-map", true);
} else if (dataType.startsWith("models::")) {
op.bodyParam.isModel = true;
} else if (dataType.equals("String")) {
op.bodyParam.isString = true;
op.bodyParam.vendorExtensions.put("is-string", true);
}
if (consumesJson) {
op.bodyParam.vendorExtensions.put("x-consumes-json", true);
} else if (consumesFormUrlEncoded) {

View File

@@ -1408,7 +1408,6 @@ public class RustServerCodegen extends AbstractRustCodegen implements CodegenCon
*
* @deprecated Avoid using this - use a different mechanism instead.
*/
@Deprecated
private static String stripNullable(String type) {
if (type.startsWith("swagger::Nullable<") && type.endsWith(">")) {
return type.substring("swagger::Nullable<".length(), type.length() - 1);

View File

@@ -1408,7 +1408,6 @@ public class RustServerCodegenDeprecated extends AbstractRustCodegen implements
*
* @deprecated Avoid using this - use a different mechanism instead.
*/
@Deprecated
private static String stripNullable(String type) {
if (type.startsWith("swagger::Nullable<") && type.endsWith(">")) {
return type.substring("swagger::Nullable<".length(), type.length() - 1);

View File

@@ -568,8 +568,12 @@ public class SpringCodegen extends AbstractJavaCodegen
(sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiUtil.java"));
}
if (!delegatePattern || delegateMethod) {
additionalProperties.put("jdk8-no-delegate", true);
}
if (delegatePattern && !delegateMethod) {
additionalProperties.put("isDelegate", true);
additionalProperties.put("isDelegate", "true");
apiTemplateFiles.put("apiDelegate.mustache", "Delegate.java");
}
@@ -1213,9 +1217,6 @@ public class SpringCodegen extends AbstractJavaCodegen
extensions.add(VendorExtension.X_SPRING_PAGINATED);
extensions.add(VendorExtension.X_VERSION_PARAM);
extensions.add(VendorExtension.X_PATTERN_MESSAGE);
extensions.add(VendorExtension.X_SIZE_MESSAGE);
extensions.add(VendorExtension.X_MINIMUM_MESSAGE);
extensions.add(VendorExtension.X_MAXIMUM_MESSAGE);
extensions.add(VendorExtension.X_SPRING_API_VERSION);
return extensions;
}

View File

@@ -52,7 +52,6 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
public static final String USE_SQUARE_BRACKETS_IN_ARRAY_NAMES = "useSquareBracketsInArrayNames";
public static final String AXIOS_VERSION = "axiosVersion";
public static final String DEFAULT_AXIOS_VERSION = "^1.6.1";
public static final String WITH_AWSV4_SIGNATURE = "withAWSV4Signature";
@Getter @Setter
protected String npmRepository = null;
@@ -61,7 +60,6 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
@Getter @Setter
protected String axiosVersion = DEFAULT_AXIOS_VERSION;
protected boolean withAWSV4Signature = false;
private String tsModelPackage = "";
@@ -73,7 +71,7 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.includeSecurityFeatures(SecurityFeature.BearerToken, SecurityFeature.AWSV4Signature));
.includeSecurityFeatures(SecurityFeature.BearerToken));
// clear import mapping (from default generator) as TS does not use it
// at the moment
@@ -96,7 +94,6 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
this.cliOptions.add(new CliOption(IMPORT_FILE_EXTENSION_SWITCH, IMPORT_FILE_EXTENSION_SWITCH_DESC, SchemaTypeUtil.STRING_TYPE).defaultValue(this.importFileExtension));
this.cliOptions.add(new CliOption(USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, "Setting this property to true will add brackets to array attribute names, e.g. my_values[].", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString()));
this.cliOptions.add(new CliOption(AXIOS_VERSION, "Use this property to override the axios version in package.json").defaultValue(DEFAULT_AXIOS_VERSION));
this.cliOptions.add(new CliOption(WITH_AWSV4_SIGNATURE, "whether to include AWS v4 signature support", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString()));
// Templates have no mapping between formatted property names and original base names so use only "original" and remove this option
removeOption(CodegenConstants.MODEL_PROPERTY_NAMING);
}
@@ -185,10 +182,6 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
setAxiosVersion(additionalProperties.get(AXIOS_VERSION).toString());
}
additionalProperties.put("axiosVersion", getAxiosVersion());
if (additionalProperties.containsKey(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT)) {
this.setWithAWSV4Signature(Boolean.parseBoolean(additionalProperties.get(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT).toString()));
}
additionalProperties.put(CodegenConstants.WITH_AWSV4_SIGNATURE_COMMENT, withAWSV4Signature);
}
@@ -314,10 +307,6 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
}
public void setWithAWSV4Signature(boolean withAWSV4Signature) {
this.withAWSV4Signature = withAWSV4Signature;
}
/**
* Overriding toRegularExpression() to avoid escapeText() being called,
* as it would return a broken regular expression if any escaped character / metacharacter were present.

View File

@@ -100,8 +100,6 @@ public class TypeScriptClientCodegen extends AbstractTypeScriptClientCodegen imp
private final DateTimeFormatter iso8601Date = DateTimeFormatter.ISO_DATE;
private final DateTimeFormatter iso8601DateTime = DateTimeFormatter.ISO_DATE_TIME;
protected String apiDocPath = "docs/";
public TypeScriptClientCodegen() {
super();
@@ -402,11 +400,6 @@ public class TypeScriptClientCodegen extends AbstractTypeScriptClientCodegen imp
return objs;
}
@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
}
private List<Map<String, String>> toTsImports(CodegenModel cm, Set<String> imports) {
List<Map<String, String>> tsImports = new ArrayList<>();
for (String im : imports) {
@@ -439,8 +432,6 @@ public class TypeScriptClientCodegen extends AbstractTypeScriptClientCodegen imp
apiPackage = this.apiPackage + ".apis";
testPackage = this.testPackage + ".tests";
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.putIfAbsent(FRAMEWORK_SWITCH, FRAMEWORKS[0]);
supportingFiles.add(new SupportingFile("index.mustache", "index.ts"));

View File

@@ -73,8 +73,6 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
protected boolean withoutRuntimeChecks = false;
protected boolean stringEnums = false;
protected String fileNaming = PASCAL_CASE;
protected String apiDocPath = "docs";
protected String modelDocPath = "docs";
// "Saga and Record" mode.
public static final String SAGAS_AND_RECORDS = "sagasAndRecords";
@@ -109,12 +107,10 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
// at the moment
importMapping.clear();
outputFolder = "generated-code" + File.separator + "typescript-fetch";
outputFolder = "generated-code/typescript-fetch";
embeddedTemplateDir = templateDir = "typescript-fetch";
this.apiTemplateFiles.put("apis.mustache", ".ts");
this.apiDocTemplateFiles.put("api_doc.mustache", ".md");
this.modelDocTemplateFiles.put("model_doc.mustache", ".md");
this.addExtraReservedWords();
@@ -142,11 +138,6 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
return convertUsingFileNamingConvention(super.toModelFilename(name));
}
@Override
public String toModelDocFilename(String name) {
return toModelName(name);
}
/**
* Converts the original name according to the current <code>fileNaming</code> strategy.
*
@@ -251,10 +242,6 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
this.apiPackage = sourceDir + "apis";
this.modelPackage = sourceDir + "models";
// make api and model doc path available in mustache template
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
supportingFiles.add(new SupportingFile("index.mustache", sourceDir, "index.ts"));
supportingFiles.add(new SupportingFile("runtime.mustache", sourceDir, "runtime.ts"));
@@ -329,16 +316,6 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
convertPropertyToBooleanAndWriteBack(VALIDATION_ATTRIBUTES, this::setGenerateValidationAttributes);
}
@Override
public String apiDocFileFolder() {
return (outputFolder + File.separator + apiDocPath);
}
@Override
public String modelDocFileFolder() {
return (outputFolder + File.separator + modelDocPath);
}
@Override
public String toEnumDefaultValue(String value, String datatype) {
if (this.getSagasAndRecords()) {
@@ -1522,16 +1499,11 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
public Set<String> oneOfArrays = new TreeSet<>();
@Getter @Setter
public Set<CodegenProperty> oneOfPrimitives = new HashSet<>();
@Getter @Setter
public CodegenDiscriminator.MappedModel selfReferencingDiscriminatorMapping;
public boolean isEntity; // Is a model containing an "id" property marked as isUniqueId
public String returnPassthrough;
public boolean hasReturnPassthroughVoid;
public boolean hasSelfReferencingDiscriminatorMapping(){
return selfReferencingDiscriminatorMapping != null;
}
public boolean isDateType() {
return isDate && "Date".equals(dataType);
}
@@ -1625,17 +1597,6 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
this.setAdditionalProperties(cm.getAdditionalProperties());
this.setIsModel(cm.getIsModel());
this.setComposedSchemas(cm.getComposedSchemas());
if (this.discriminator != null) {
Set<CodegenDiscriminator.MappedModel> mappedModels = this.discriminator.getMappedModels();
for(CodegenDiscriminator.MappedModel mappedModel : mappedModels) {
if(mappedModel.getModelName().equals(cm.classname)) {
this.selfReferencingDiscriminatorMapping = mappedModel;
}
}
if(this.selfReferencingDiscriminatorMapping != null) {
this.discriminator.getMappedModels().remove(this.selfReferencingDiscriminatorMapping);
}
}
}
@Override

View File

@@ -1299,9 +1299,11 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
try {
response = sendRequest(method, invocationBuilder, entity);
final int statusCode = response.getStatusInfo().getStatusCode();
{{#hasOAuthMethods}}
// If OAuth is used and a status 401 is received, renew the access token and retry the request
if (authNames != null && response.getStatusInfo().getStatusCode() == Status.UNAUTHORIZED.getStatusCode()) {
if (authNames != null && statusCode == Status.UNAUTHORIZED.getStatusCode()) {
for (String authName : authNames) {
Authentication authentication = authentications.get(authName);
if (authentication instanceof OAuth) {
@@ -1315,10 +1317,8 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
}
}
}
{{/hasOAuthMethods}}
final int statusCode = response.getStatusInfo().getStatusCode();
{{/hasOAuthMethods}}
Map<String, List<String>> responseHeaders = buildResponseHeaders(response);
if (statusCode == Status.NO_CONTENT.getStatusCode()) {

View File

@@ -1299,9 +1299,11 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
try {
response = sendRequest(method, invocationBuilder, entity);
final int statusCode = response.getStatusInfo().getStatusCode();
{{#hasOAuthMethods}}
// If OAuth is used and a status 401 is received, renew the access token and retry the request
if (authNames != null && response.getStatusInfo().getStatusCode() == Status.UNAUTHORIZED.getStatusCode()) {
if (authNames != null && statusCode == Status.UNAUTHORIZED.getStatusCode()) {
for (String authName : authNames) {
Authentication authentication = authentications.get(authName);
if (authentication instanceof OAuth) {
@@ -1317,8 +1319,6 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
}
{{/hasOAuthMethods}}
final int statusCode = response.getStatusInfo().getStatusCode();
Map<String, List<String>> responseHeaders = buildResponseHeaders(response);
if (statusCode == Status.NO_CONTENT.getStatusCode()) {

View File

@@ -1,11 +1,7 @@
{{#withXml}}
@XmlType(name="{{datatypeWithEnum}}")
@XmlEnum({{dataType}}.class)
{{/withXml}}
{{>additionalEnumTypeAnnotations}}public enum {{datatypeWithEnum}} {
{{#allowableValues}}
{{#enumVars}}{{#withXml}}@XmlEnumValue({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}){{/withXml}}{{name}}({{dataType}}.valueOf({{{value}}})){{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}
{{#enumVars}}{{name}}({{dataType}}.valueOf({{{value}}})){{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}
{{/allowableValues}}

View File

@@ -7,23 +7,13 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.annotation.JsonTypeName;
{{#withXml}}
import {{javaxPackage}}.xml.bind.annotation.XmlElement;
import {{javaxPackage}}.xml.bind.annotation.XmlRootElement;
import {{javaxPackage}}.xml.bind.annotation.XmlAccessType;
import {{javaxPackage}}.xml.bind.annotation.XmlAccessorType;
import {{javaxPackage}}.xml.bind.annotation.XmlType;
import {{javaxPackage}}.xml.bind.annotation.XmlEnum;
import {{javaxPackage}}.xml.bind.annotation.XmlEnumValue;
{{/withXml}}
{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/**
* {{.}}
**/{{/description}}
{{#useSwaggerAnnotations}}{{#description}}@ApiModel(description = "{{{.}}}"){{/description}}{{/useSwaggerAnnotations}}{{#useMicroProfileOpenAPIAnnotations}}
@org.eclipse.microprofile.openapi.annotations.media.Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}){{/useMicroProfileOpenAPIAnnotations}}
@JsonTypeName("{{name}}")
{{>generatedAnnotation}}{{>additionalModelTypeAnnotations}}{{>xmlPojoAnnotation}}
{{>generatedAnnotation}}{{>additionalModelTypeAnnotations}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}
@@ -102,9 +92,6 @@ public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}} {{#vendorExtens
return this;
}
{{#withXml}}
@XmlElement(name="{{baseName}}"{{#required}}, required = {{required}}{{/required}})
{{/withXml}}
{{#vendorExtensions.x-extra-annotation}}{{{vendorExtensions.x-extra-annotation}}}{{/vendorExtensions.x-extra-annotation}}{{#useSwaggerAnnotations}}
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{/useSwaggerAnnotations}}{{#useMicroProfileOpenAPIAnnotations}}
@org.eclipse.microprofile.openapi.annotations.media.Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useMicroProfileOpenAPIAnnotations}}

View File

@@ -1,8 +0,0 @@
{{#withXml}}
@XmlAccessorType(XmlAccessType.FIELD)
{{#hasVars}} @XmlType(name = "{{classname}}", propOrder =
{ {{#vars}}"{{name}}"{{^-last}}, {{/-last}}{{/vars}}
}){{/hasVars}}
{{^hasVars}}@XmlType(name = "{{classname}}"){{/hasVars}}
{{^parent}}@XmlRootElement(name="{{classname}}"){{/parent}}
{{/withXml}}

View File

@@ -24,16 +24,14 @@ import io.swagger.v3.oas.annotations.media.ExampleObject;
{{#swagger1AnnotationLibrary}}
import io.swagger.annotations.*;
{{/swagger1AnnotationLibrary}}
{{^isDelegate}}
{{#jdk8-default-interface}}
{{#jdk8-no-delegate}}
{{#virtualService}}
import io.virtualan.annotation.ApiVirtual;
import io.virtualan.annotation.VirtualService;
{{/virtualService}}
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
{{/jdk8-default-interface}}
{{/isDelegate}}
{{/jdk8-no-delegate}}
{{^useResponseEntity}}
import org.springframework.http.HttpStatus;
{{/useResponseEntity}}
@@ -50,13 +48,11 @@ import org.springframework.web.bind.annotation.RestController;
{{/useResponseEntity}}
{{/useSpringController}}
import org.springframework.web.bind.annotation.*;
{{#jdk8-default-interface}}
{{^isDelegate}}
{{^reactive}}
{{#jdk8-no-delegate}}
{{^reactive}}
import org.springframework.web.context.request.NativeWebRequest;
{{/reactive}}
{{/isDelegate}}
{{/jdk8-default-interface}}
{{/reactive}}
{{/jdk8-no-delegate}}
import org.springframework.web.multipart.MultipartFile;
{{#reactive}}
import org.springframework.web.server.ServerWebExchange;
@@ -71,14 +67,14 @@ import {{javaxPackage}}.validation.constraints.*;
{{/useBeanValidation}}
import java.util.List;
import java.util.Map;
{{^isDelegate}}
{{#jdk8-no-delegate}}
import java.util.Optional;
{{/isDelegate}}
{{#isDelegate}}
{{/jdk8-no-delegate}}
{{^jdk8-no-delegate}}
{{#useOptional}}
import java.util.Optional;
{{/useOptional}}
{{/isDelegate}}
{{/jdk8-no-delegate}}
{{#async}}
import java.util.concurrent.CompletableFuture;
{{/async}}
@@ -132,7 +128,7 @@ public interface {{classname}} {
{{/jdk8-default-interface}}
{{#operation}}
String PATH_{{#lambda.uppercase}}{{#lambda.snakecase}}{{{operationId}}}{{/lambda.snakecase}}{{/lambda.uppercase}} = "{{{path}}}";
public static final String PATH_{{#lambda.uppercase}}{{#lambda.snakecase}}{{{operationId}}}{{/lambda.snakecase}}{{/lambda.uppercase}} = "{{{path}}}";
/**
* {{httpMethod}} {{{path}}}{{#summary}} : {{.}}{{/summary}}
{{#notes}}
@@ -265,9 +261,7 @@ public interface {{classname}} {
{{#vendorExtensions.x-operation-extra-annotation}}
{{{.}}}
{{/vendorExtensions.x-operation-extra-annotation}}
{{#vendorExtensions.x-sse}}
@ResponseBody
{{/vendorExtensions.x-sse}}
{{#vendorExtensions.x-sse}}@ResponseBody{{/vendorExtensions.x-sse}}
{{#jdk8-default-interface}}default {{/jdk8-default-interface}}{{>responseType}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}(
{{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}},
{{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}},

View File

@@ -1,24 +1,24 @@
{{^isUuid}}{{#pattern}}{{^isByteArray}}@Pattern(regexp = "{{{pattern}}}"{{#vendorExtensions.x-pattern-message}}, message = "{{vendorExtensions.x-pattern-message}}"{{/vendorExtensions.x-pattern-message}}) {{/isByteArray}}{{/pattern}}{{!
{{^isUuid}}{{#pattern}}{{^isByteArray}}@Pattern(regexp = "{{{pattern}}}"{{#vendorExtensions.x-pattern-message}}, message="{{vendorExtensions.x-pattern-message}}"{{/vendorExtensions.x-pattern-message}}) {{/isByteArray}}{{/pattern}}{{!
minLength && maxLength set
}}{{#minLength}}{{#maxLength}}@Size(min = {{minLength}}, max = {{maxLength}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
}}{{#minLength}}{{#maxLength}}@Size(min = {{minLength}}, max = {{maxLength}}) {{/maxLength}}{{/minLength}}{{!
minLength set, maxLength not
}}{{#minLength}}{{^maxLength}}@Size(min = {{minLength}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
}}{{#minLength}}{{^maxLength}}@Size(min = {{minLength}}) {{/maxLength}}{{/minLength}}{{!
minLength not set, maxLength set
}}{{^minLength}}{{#maxLength}}@Size(max = {{.}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
}}{{^minLength}}{{#maxLength}}@Size(max = {{.}}) {{/maxLength}}{{/minLength}}{{!
@Size: minItems && maxItems set
}}{{#minItems}}{{#maxItems}}@Size(min = {{minItems}}, max = {{maxItems}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
}}{{#minItems}}{{#maxItems}}@Size(min = {{minItems}}, max = {{maxItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems set, maxItems not
}}{{#minItems}}{{^maxItems}}@Size(min = {{minItems}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
}}{{#minItems}}{{^maxItems}}@Size(min = {{minItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems not set && maxItems set
}}{{^minItems}}{{#maxItems}}@Size(max = {{.}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
}}{{^minItems}}{{#maxItems}}@Size(max = {{.}}) {{/maxItems}}{{/minItems}}{{!
@Email: useBeanValidation
}}{{#isEmail}}{{#useBeanValidation}}@{{javaxPackage}}.validation.constraints.Email {{/useBeanValidation}}{{!
@Email: performBeanValidation exclusive
}}{{^useBeanValidation}}{{#performBeanValidation}}@org.hibernate.validator.constraints.Email {{/performBeanValidation}}{{/useBeanValidation}}{{/isEmail}}{{!
check for integer or long / all others=decimal type with @Decimal*
isInteger set
}}{{#isInteger}}{{#minimum}}@Min(value = {{.}}{{#vendorExtensions.x-minimum-message}}, message = "{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}) {{/minimum}}{{#maximum}}@Max(value = {{.}}{{#vendorExtensions.x-maximum-message}}, message = "{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}) {{/maximum}}{{/isInteger}}{{!
}}{{#isInteger}}{{#minimum}}@Min({{.}}) {{/minimum}}{{#maximum}}@Max({{.}}) {{/maximum}}{{/isInteger}}{{!
isLong set
}}{{#isLong}}{{#minimum}}@Min(value = {{.}}L{{#vendorExtensions.x-minimum-message}}, message = "{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}) {{/minimum}}{{#maximum}}@Max(value = {{.}}L{{#vendorExtensions.x-maximum-message}}, message = "{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}) {{/maximum}}{{/isLong}}{{!
}}{{#isLong}}{{#minimum}}@Min({{.}}L) {{/minimum}}{{#maximum}}@Max({{.}}L) {{/maximum}}{{/isLong}}{{!
Not Integer, not Long => we have a decimal value!
}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin(value = "{{minimum}}"{{#exclusiveMinimum}}, inclusive = false{{/exclusiveMinimum}}{{#vendorExtensions.x-minimum-message}}, message = "{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}) {{/minimum}}{{#maximum}}@DecimalMax(value = "{{maximum}}"{{#exclusiveMaximum}}, inclusive = false{{/exclusiveMaximum}}{{#vendorExtensions.x-maximum-message}}, message = "{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}) {{/maximum}}{{/isLong}}{{/isInteger}}{{/isUuid}}
}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin({{#exclusiveMinimum}}value = {{/exclusiveMinimum}}"{{minimum}}"{{#exclusiveMinimum}}, inclusive = false{{/exclusiveMinimum}}) {{/minimum}}{{#maximum}}@DecimalMax({{#exclusiveMaximum}}value = {{/exclusiveMaximum}}"{{maximum}}"{{#exclusiveMaximum}}, inclusive = false{{/exclusiveMaximum}}) {{/maximum}}{{/isLong}}{{/isInteger}}{{/isUuid}}

View File

@@ -167,9 +167,6 @@ namespace {{packageName}}.Client
/// </remarks>
{{>visibility}} partial class ApiClient : IDisposable, ISynchronousClient{{#supportsAsync}}, IAsynchronousClient{{/supportsAsync}}
{
{{#net60OrLater}}
private static readonly HttpRequestOptionsKey<List<Cookie>> _httpOptionsCookieContainerKey = new("CookieContainer");
{{/net60OrLater}}
private readonly string _baseUrl;
private readonly HttpClientHandler _httpClientHandler;
@@ -385,15 +382,12 @@ namespace {{packageName}}.Client
}
}
// TODO provide an alternative that allows cookies per request instead of per API client
if (options.Cookies != null && options.Cookies.Count > 0)
{
{{#net60OrLater}}
request.Options.Set(_httpOptionsCookieContainerKey, options.Cookies);
{{/net60OrLater}}
{{^net60OrLater}}
request.Properties["CookieContainer"] = options.Cookies;
{{/net60OrLater}}
}
return request;
@@ -480,16 +474,9 @@ namespace {{packageName}}.Client
_httpClientHandler.ClientCertificates.AddRange(configuration.ClientCertificates);
}
{{^net60OrLater}}
var cookieContainer = req.Properties.ContainsKey("CookieContainer") ? req.Properties["CookieContainer"] as List<Cookie> : null;
{{/net60OrLater}}
{{#net60OrLater}}
if (req.Options.TryGetValue(_httpOptionsCookieContainerKey, out var cookieContainer))
{{/net60OrLater}}
{{^net60OrLater}}
if (cookieContainer != null)
{{/net60OrLater}}
{
if(_httpClientHandler == null) throw new InvalidOperationException("Request property `CookieContainer` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
foreach (var cookie in cookieContainer)

View File

@@ -34,7 +34,7 @@ namespace {{packageName}}.{{clientPackage}}
string value = reader.GetString(){{nrt!}};
foreach(string format in Formats)
if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly result))
if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out DateOnly result))
return result;
throw new NotSupportedException();

View File

@@ -34,7 +34,7 @@ namespace {{packageName}}.{{clientPackage}}
string value = reader.GetString(){{nrt!}};
foreach(string format in Formats)
if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly result))
if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out DateOnly result))
return result;
throw new NotSupportedException();

View File

@@ -79,7 +79,7 @@ namespace {{packageName}}.Client
public async Task<T> Deserialize<T>(HttpResponseMessage response)
{
var result = (T)await Deserialize(response, typeof(T)).ConfigureAwait(false);
var result = (T) await Deserialize(response, typeof(T)).ConfigureAwait(false);
return result;
}
@@ -95,13 +95,13 @@ namespace {{packageName}}.Client
// process response headers, e.g. Access-Control-Allow-Methods
foreach (var responseHeader in response.Headers)
{
headers.Add(responseHeader.Key + "=" + ClientUtils.ParameterToString(responseHeader.Value));
headers.Add(responseHeader.Key + "=" + ClientUtils.ParameterToString(responseHeader.Value));
}
// process response content headers, e.g. Content-Type
foreach (var responseHeader in response.Content.Headers)
{
headers.Add(responseHeader.Key + "=" + ClientUtils.ParameterToString(responseHeader.Value));
headers.Add(responseHeader.Key + "=" + ClientUtils.ParameterToString(responseHeader.Value));
}
// RFC 2183 & RFC 2616
@@ -112,8 +112,7 @@ namespace {{packageName}}.Client
}
else if (type == typeof(FileParameter))
{
if (headers != null)
{
if (headers != null) {
foreach (var header in headers)
{
var match = fileNameRegex.Match(header.ToString());
@@ -192,9 +191,6 @@ namespace {{packageName}}.Client
/// </remarks>
{{>visibility}} partial class ApiClient : IDisposable, ISynchronousClient{{#supportsAsync}}, IAsynchronousClient{{/supportsAsync}}
{
{{#net60OrLater}}
private static readonly HttpRequestOptionsKey<List<Cookie>> _httpOptionsCookieContainerKey = new("CookieContainer");
{{/net60OrLater}}
private readonly string _baseUrl;
private readonly HttpClientHandler _httpClientHandler;
@@ -287,8 +283,7 @@ namespace {{packageName}}.Client
/// </summary>
public void Dispose()
{
if(_disposeClient)
{
if(_disposeClient) {
_httpClient.Dispose();
}
}
@@ -418,12 +413,7 @@ namespace {{packageName}}.Client
// TODO provide an alternative that allows cookies per request instead of per API client
if (options.Cookies != null && options.Cookies.Count > 0)
{
{{#net60OrLater}}
request.Options.Set(_httpOptionsCookieContainerKey, options.Cookies);
{{/net60OrLater}}
{{^net60OrLater}}
request.Properties["CookieContainer"] = options.Cookies;
{{/net60OrLater}}
}
return request;
@@ -434,7 +424,7 @@ namespace {{packageName}}.Client
private async Task<ApiResponse<T>> ToApiResponse<T>(HttpResponseMessage response, object responseData, Uri uri)
{
T result = (T)responseData;
T result = (T) responseData;
string rawContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var transformed = new ApiResponse<T>(response.StatusCode, new Multimap<string, string>({{#caseInsensitiveResponseHeaders}}StringComparer.OrdinalIgnoreCase{{/caseInsensitiveResponseHeaders}}), result, rawContent)
@@ -469,7 +459,7 @@ namespace {{packageName}}.Client
transformed.Cookies.Add(cookie);
}
}
catch (PlatformNotSupportedException) { }
catch (PlatformNotSupportedException) {}
}
return transformed;
@@ -506,22 +496,15 @@ namespace {{packageName}}.Client
if (configuration.ClientCertificates != null)
{
if (_httpClientHandler == null) throw new InvalidOperationException("Configuration `ClientCertificates` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
if(_httpClientHandler == null) throw new InvalidOperationException("Configuration `ClientCertificates` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
_httpClientHandler.ClientCertificates.AddRange(configuration.ClientCertificates);
}
{{^net60OrLater}}
var cookieContainer = req.Properties.ContainsKey("CookieContainer") ? req.Properties["CookieContainer"] as List<Cookie> : null;
{{/net60OrLater}}
{{#net60OrLater}}
if (req.Options.TryGetValue(_httpOptionsCookieContainerKey, out var cookieContainer))
{{/net60OrLater}}
{{^net60OrLater}}
if (cookieContainer != null)
{{/net60OrLater}}
{
if (_httpClientHandler == null) throw new InvalidOperationException("Request property `CookieContainer` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
if(_httpClientHandler == null) throw new InvalidOperationException("Request property `CookieContainer` not supported when the client is explicitly created without an HttpClientHandler, use the proper constructor.");
foreach (var cookie in cookieContainer)
{
_httpClientHandler.CookieContainer.Add(cookie);
@@ -563,11 +546,11 @@ namespace {{packageName}}.Client
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
if (typeof({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
{
responseData = (T)typeof(T).GetMethod("FromJson").Invoke(null, new object[] { response.Content });
responseData = (T) typeof(T).GetMethod("FromJson").Invoke(null, new object[] { response.Content });
}
else if (typeof(T).Name == "Stream") // for binary response
{
responseData = (T)(object) await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
responseData = (T) (object) await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
}
InterceptResponse(req, response);

View File

@@ -32,7 +32,7 @@
@BuiltValueHook(initializeBuilder: true)
static void _defaults({{{classname}}}Builder b) => b{{#vendorExtensions.x-parent-discriminator}}..{{propertyName}}=b.discriminatorValue{{/vendorExtensions.x-parent-discriminator}}{{#vendorExtensions.x-self-and-ancestor-only-props}}{{#defaultValue}}
..{{{name}}} = {{#isEnum}}{{^isContainer}}{{#enumName}}{{enumName}}.valueOf({{{defaultValue}}}){{/enumName}}{{^enumName}}{{{defaultValue}}}{{/enumName}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{defaultValue}}}{{/isEnum}}{{/defaultValue}}{{/vendorExtensions.x-self-and-ancestor-only-props}};
..{{{name}}} = {{#isEnum}}{{^isContainer}}{{{defaultValue}}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{defaultValue}}}{{/isEnum}}{{/defaultValue}}{{/vendorExtensions.x-self-and-ancestor-only-props}};
{{/vendorExtensions.x-is-parent}} @BuiltValueSerializer(custom: true)
static Serializer<{{classname}}> get serializer => _${{classname}}Serializer();

View File

@@ -1,6 +1,6 @@
package {{package}};
{{^isDelegate}}
{{^jdk8-no-delegate}}
{{#imports}}import {{import}};
{{/imports}}
@@ -8,9 +8,9 @@ import io.swagger.annotations.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
{{/isDelegate}}
{{/jdk8-no-delegate}}
import org.springframework.stereotype.Controller;
{{^isDelegate}}
{{^jdk8-no-delegate}}
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
@@ -26,7 +26,7 @@ import java.util.Optional;
{{#async}}
import java.util.concurrent.Callable;
{{/async}}
{{/isDelegate}}
{{/jdk8-no-delegate}}
{{^useSpringCloudClient}}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
@@ -60,7 +60,7 @@ public class {{classname}}Controller implements {{classname}} {
}
{{/isDelegate}}
{{^isDelegate}}
{{^jdk8-no-delegate}}
{{#operation}}
public {{#async}}Callable<{{/async}}ResponseEntity<{{>returnTypes}}>{{#async}}>{{/async}} {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}},
{{/allParams}}@RequestHeader(value = "Accept", required = false) String accept) throws Exception {
@@ -111,6 +111,6 @@ public class {{classname}}Controller implements {{classname}} {
}
{{/operation}}
{{/isDelegate}}
{{/jdk8-no-delegate}}
}
{{/operations}}

View File

@@ -18,9 +18,9 @@ public class {{classname}}MockServer {
@Deprecated
{{/isDeprecated}}
public static MappingBuilder stub{{#lambda.pascalcase}}{{operationId}}{{/lambda.pascalcase}}{{{code}}}({{#allParams}}{{#required}}{{#isNullable}}@{{javaxPackage}}.annotation.Nullable {{/isNullable}}{{^isNullable}}@{{javaxPackage}}.annotation.Nonnull {{/isNullable}}{{/required}}{{^required}}@{{javaxPackage}}.annotation.Nullable {{/required}}{{^isBodyParam}}String {{paramName}}{{/isBodyParam}}{{#isBodyParam}}String body{{/isBodyParam}}{{^-last}}, {{/-last}}{{#-last}}{{#headers.0}}, {{/headers.0}}{{^headers.0}}{{#returnType}}, {{/returnType}}{{/headers.0}}{{/-last}}{{/allParams}}{{#headers}}String response{{#lambda.pascalcase}}{{baseName}}{{/lambda.pascalcase}}{{^-last}}, {{/-last}}{{#-last}}{{#returnType}}, {{/returnType}}{{/-last}}{{/headers}}{{#returnType}}String response{{/returnType}}) {
MappingBuilder stub = {{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}({{^pathParams.0}}urlPathEqualTo{{/pathParams.0}}{{#pathParams.0}}urlPathTemplate{{/pathParams.0}}("{{{path}}}")){{#hasProduces}}{{#produces}}
.withHeader("Accept", containing("{{{mediaType}}}")){{/produces}}{{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly(equalToIgnoreCase("{{#consumes.0}}{{{mediaType}}}{{/consumes.0}}"))){{/hasConsumes}}
MappingBuilder stub = {{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}({{^pathParams.0}}urlPathEqualTo{{/pathParams.0}}{{#pathParams.0}}urlPathTemplate{{/pathParams.0}}("{{{path}}}")){{#hasProduces}}
.withHeader("Accept", havingExactly({{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}})){{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly("{{#consumes.0}}{{{mediaType}}}{{/consumes.0}}")){{/hasConsumes}}
.withHeader("Authorization", matching(".*")){{/hasAuthMethods}}{{#cookieParams}}
.withCookie("{{baseName}}", havingExactly({{paramName}})){{/cookieParams}}{{#hasBodyParam}}
.withRequestBody(equalToJson(body)){{/hasBodyParam}}
@@ -105,9 +105,9 @@ public class {{classname}}MockServer {
{{/responses}}
public static MappingBuilder stub{{#lambda.pascalcase}}{{operationId}}{{/lambda.pascalcase}}Fault({{#allParams}}{{#required}}{{#isNullable}}@{{javaxPackage}}.annotation.Nullable {{/isNullable}}{{^isNullable}}@{{javaxPackage}}.annotation.Nonnull {{/isNullable}}{{/required}}{{^required}}@{{javaxPackage}}.annotation.Nullable {{/required}}{{^isBodyParam}}String {{paramName}}{{/isBodyParam}}{{#isBodyParam}}String body{{/isBodyParam}}, {{/allParams}}Fault fault) {
MappingBuilder stub = {{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}({{^pathParams.0}}urlPathEqualTo{{/pathParams.0}}{{#pathParams.0}}urlPathTemplate{{/pathParams.0}}("{{{path}}}")){{#hasProduces}}{{#produces}}
.withHeader("Accept", containing("{{{mediaType}}}")){{/produces}}{{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly(equalToIgnoreCase("{{#consumes.0}}{{{mediaType}}}{{/consumes.0}}"))){{/hasConsumes}}
MappingBuilder stub = {{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}({{^pathParams.0}}urlPathEqualTo{{/pathParams.0}}{{#pathParams.0}}urlPathTemplate{{/pathParams.0}}("{{{path}}}")){{#hasProduces}}
.withHeader("Accept", havingExactly({{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}})){{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly("{{#consumes.0}}{{{mediaType}}}{{/consumes.0}}")){{/hasConsumes}}
.withHeader("Authorization", matching(".*")){{/hasAuthMethods}}{{#cookieParams}}
.withCookie("{{baseName}}", havingExactly({{paramName}})){{/cookieParams}}{{#bodyParam}}
.withRequestBody(equalToJson(body)){{/bodyParam}}

View File

@@ -37,14 +37,14 @@ apply plugin: "java"
apply plugin: "kotlin"
apply plugin: "application"
sourceCompatibility = 11
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "1.8"
}
repositories {

View File

@@ -1,22 +1,22 @@
{{#isEmail}}@Email {{/isEmail}}{{!
pattern set
}}{{#pattern}}@Pattern(regexp="{{{.}}}"{{#vendorExtensions.x-pattern-message}}, message="{{vendorExtensions.x-pattern-message}}"{{/vendorExtensions.x-pattern-message}}) {{/pattern}}{{!
}}{{#pattern}}@Pattern(regexp="{{{.}}}") {{/pattern}}{{!
minLength && maxLength set
}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{!
minLength set, maxLength not
}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{!
minLength not set, maxLength set
}}{{^minLength}}{{#maxLength}}@Size(max={{.}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
}}{{^minLength}}{{#maxLength}}@Size(max={{.}}) {{/maxLength}}{{/minLength}}{{!
@Size: minItems && maxItems set
}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems set, maxItems not
}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems not set && maxItems set
}}{{^minItems}}{{#maxItems}}@Size(max={{.}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
}}{{^minItems}}{{#maxItems}}@Size(max={{.}}) {{/maxItems}}{{/minItems}}{{!
check for integer or long / all others=decimal type with @Decimal*
isInteger set
}}{{#isInteger}}{{#minimum}}@Min(value={{.}}{{#vendorExtensions.x-minimum-message}}, message="{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}){{/minimum}}{{#maximum}} @Max(value={{.}}{{#vendorExtensions.x-maximum-message}}, message="{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}) {{/maximum}}{{/isInteger}}{{!
}}{{#isInteger}}{{#minimum}}@Min({{.}}){{/minimum}}{{#maximum}} @Max({{.}}) {{/maximum}}{{/isInteger}}{{!
isLong set
}}{{#isLong}}{{#minimum}}@Min(value={{.}}L{{#vendorExtensions.x-minimum-message}}, message="{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}){{/minimum}}{{#maximum}} @Max(value={{.}}L{{#vendorExtensions.x-maximum-message}}, message="{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}) {{/maximum}}{{/isLong}}{{!
}}{{#isLong}}{{#minimum}}@Min({{.}}L){{/minimum}}{{#maximum}} @Max({{.}}L) {{/maximum}}{{/isLong}}{{!
Not Integer, not Long => we have a decimal value!
}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin(value="{{.}}"{{#vendorExtensions.x-minimum-message}}, message="{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}){{/minimum}}{{#maximum}} @DecimalMax(value="{{.}}"{{#vendorExtensions.x-maximum-message}}, message="{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}) {{/maximum}}{{/isLong}}{{/isInteger}}
}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin("{{.}}"){{/minimum}}{{#maximum}} @DecimalMax("{{.}}") {{/maximum}}{{/isLong}}{{/isInteger}}

View File

@@ -7,32 +7,32 @@ pattern set
@get:Pattern(regexp="{{{pattern}}}"{{#vendorExtensions.x-pattern-message}}, message="{{vendorExtensions.x-pattern-message}}"{{/vendorExtensions.x-pattern-message}}){{/pattern}}{{!
minLength && maxLength set
}}{{#minLength}}{{#maxLength}}
@get:Size(min={{minLength}},max={{maxLength}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}){{/maxLength}}{{/minLength}}{{!
@get:Size(min={{minLength}},max={{maxLength}}){{/maxLength}}{{/minLength}}{{!
minLength set, maxLength not
}}{{#minLength}}{{^maxLength}}
@get:Size(min={{minLength}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}){{/maxLength}}{{/minLength}}{{!
@get:Size(min={{minLength}}){{/maxLength}}{{/minLength}}{{!
minLength not set, maxLength set
}}{{^minLength}}{{#maxLength}}
@get:Size(max={{.}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}){{/maxLength}}{{/minLength}}{{!
@get:Size(max={{.}}){{/maxLength}}{{/minLength}}{{!
@Size: minItems && maxItems set
}}{{#minItems}}{{#maxItems}}
@get:Size(min={{minItems}},max={{maxItems}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
@get:Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems set, maxItems not
}}{{#minItems}}{{^maxItems}}
@get:Size(min={{minItems}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}){{/maxItems}}{{/minItems}}{{!
@get:Size(min={{minItems}}){{/maxItems}}{{/minItems}}{{!
@Size: minItems not set && maxItems set
}}{{^minItems}}{{#maxItems}}
@get:Size(max={{.}}{{#vendorExtensions.x-size-message}}, message="{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}){{/maxItems}}{{/minItems}}{{!
@get:Size(max={{.}}){{/maxItems}}{{/minItems}}{{!
check for integer or long / all others=decimal type with @Decimal*
isInteger set
}}{{#isInteger}}{{#minimum}}
@get:Min(value={{.}}{{#vendorExtensions.x-minimum-message}}, message="{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}){{/minimum}}{{#maximum}}
@get:Max(value={{.}}{{#vendorExtensions.x-maximum-message}}, message="{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}){{/maximum}}{{/isInteger}}{{!
@get:Min({{.}}){{/minimum}}{{#maximum}}
@get:Max({{.}}){{/maximum}}{{/isInteger}}{{!
isLong set
}}{{#isLong}}{{#minimum}}
@get:Min(value={{.}}L{{#vendorExtensions.x-minimum-message}}, message="{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}){{/minimum}}{{#maximum}}
@get:Max(value={{.}}L{{#vendorExtensions.x-maximum-message}}, message="{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}){{/maximum}}{{/isLong}}{{!
@get:Min({{.}}L){{/minimum}}{{#maximum}}
@get:Max({{.}}L){{/maximum}}{{/isLong}}{{!
Not Integer, not Long => we have a decimal value!
}}{{^isInteger}}{{^isLong}}{{#minimum}}
@get:DecimalMin(value="{{.}}"{{#vendorExtensions.x-minimum-message}}, message="{{vendorExtensions.x-minimum-message}}"{{/vendorExtensions.x-minimum-message}}){{/minimum}}{{#maximum}}
@get:DecimalMax(value="{{.}}"{{#vendorExtensions.x-maximum-message}}, message="{{vendorExtensions.x-maximum-message}}"{{/vendorExtensions.x-maximum-message}}){{/maximum}}{{/isLong}}{{/isInteger}}
@get:DecimalMin("{{.}}"){{/minimum}}{{#maximum}}
@get:DecimalMax("{{.}}"){{/maximum}}{{/isLong}}{{/isInteger}}

View File

@@ -1 +1 @@
{{#isHeaderParam}}{{#useBeanValidation}}{{>beanValidationCore}}{{/useBeanValidation}}{{#swagger2AnnotationLibrary}}@Parameter(description = "{{{description}}}", `in` = ParameterIn.HEADER{{#required}}, required = true{{/required}}{{#allowableValues}}{{#defaultValue}}, schema = Schema(allowableValues = [{{#values}}"{{{.}}}"{{^-last}}, {{/-last}}{{/values}}]{{^isContainer}}, defaultValue = {{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}{{{defaultValue}}}{{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}{{/isContainer}}){{/defaultValue}}{{/allowableValues}}{{#allowableValues}}{{^defaultValue}}, schema = Schema(allowableValues = [{{#values}}"{{{.}}}"{{^-last}}, {{/-last}}{{/values}}]){{/defaultValue}}{{/allowableValues}}{{^allowableValues}}{{#defaultValue}}{{^isContainer}}, schema = Schema(defaultValue = {{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}{{{defaultValue}}}{{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}){{/isContainer}}{{/defaultValue}}{{/allowableValues}}){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/swagger1AnnotationLibrary}} @RequestHeader(value = "{{baseName}}", required = {{#required}}true{{/required}}{{^required}}false{{/required}}{{#defaultValue}}, defaultValue = {{^isString}}"{{{.}}}"{{/isString}}{{#isString}}{{#isEnum}}"{{{.}}}"{{/isEnum}}{{^isEnum}}{{{.}}}{{/isEnum}}{{/isString}}{{/defaultValue}}) {{{paramName}}}: {{>optionalDataType}}{{/isHeaderParam}}
{{#isHeaderParam}}{{#useBeanValidation}}{{>beanValidationCore}}{{/useBeanValidation}}{{#swagger2AnnotationLibrary}}@Parameter(description = "{{{description}}}", `in` = ParameterIn.HEADER{{#required}}, required = true{{/required}}{{#allowableValues}}{{#defaultValue}}, schema = Schema(allowableValues = [{{#values}}"{{{.}}}"{{^-last}}, {{/-last}}{{/values}}]{{^isContainer}}, defaultValue = {{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}{{{defaultValue}}}{{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}{{/isContainer}}){{/defaultValue}}{{/allowableValues}}{{#allowableValues}}{{^defaultValue}}, schema = Schema(allowableValues = [{{#values}}"{{{.}}}"{{^-last}}, {{/-last}}{{/values}}]){{/defaultValue}}{{/allowableValues}}{{^allowableValues}}{{#defaultValue}}{{^isContainer}}, schema = Schema(defaultValue = {{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}{{{defaultValue}}}{{^isString}}"{{/isString}}{{#isString}}{{#isEnum}}"{{/isEnum}}{{/isString}}){{/isContainer}}{{/defaultValue}}{{/allowableValues}}){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/swagger1AnnotationLibrary}} @RequestHeader(value = "{{baseName}}", required = {{#required}}true{{/required}}{{^required}}false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}) {{{paramName}}}: {{>optionalDataType}}{{/isHeaderParam}}

View File

@@ -17,7 +17,7 @@ repositories {
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "1.8"
}
{{#interfaceOnly}}

View File

@@ -59,7 +59,7 @@
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>11</jvmTarget>
<jvmTarget>1.8</jvmTarget>
</configuration>
<executions>
<execution>

View File

@@ -69,7 +69,7 @@
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>11</jvmTarget>
<jvmTarget>1.8</jvmTarget>
</configuration>
<executions>
<execution>

View File

@@ -1 +1 @@
{{^isFile}}{{{dataType}}}{{^required}}{{^defaultValue}}?{{/defaultValue}}{{/required}}{{/isFile}}{{#isFile}}{{#isArray}}Array<{{/isArray}}org.springframework.web.multipart.MultipartFile{{#isArray}}>{{/isArray}}{{#isNullable}}?{{/isNullable}}{{/isFile}}
{{^isFile}}{{{dataType}}}{{^required}}{{^defaultValue}}?{{/defaultValue}}{{/required}}{{/isFile}}{{#isFile}}{{#isArray}}Array<{{/isArray}}org.springframework.web.multipart.MultipartFile{{#isArray}}>{{/isArray}}{{^isArray}}{{^required}}?{{/required}}{{/isArray}}{{/isFile}}

View File

@@ -7,13 +7,6 @@ use validator::Validate;
use crate::header;
use crate::{models, types::*};
#[allow(dead_code)]
fn from_validation_error(e: validator::ValidationError) -> validator::ValidationErrors {
let mut errs = validator::ValidationErrors::new();
errs.add("na", e);
errs
}
#[allow(dead_code)]
pub fn check_xss_string(v: &str) -> std::result::Result<(), validator::ValidationError> {
if ammonia::is_html(v) {
@@ -472,7 +465,7 @@ pub fn check_xss_map<T>(v: &std::collections::HashMap<String, T>) -> std::result
#[serde(default)]
{{/required}}
pub {{{paramName}}}: {{{dataType}}},
{{/isArray}}
{{/isArray}}
{{^isArray}}
{{#required}}
pub {{{paramName}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}},
@@ -587,36 +580,10 @@ impl std::str::FromStr for {{{classname}}} {
#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
{{/isMap}}
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
pub struct {{{classname}}}(pub {{{dataType}}});
pub struct {{{classname}}}({{{dataType}}});
impl validator::Validate for {{{classname}}} {
fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
{{^isNullable}}
{{#vendorExtensions.is-nested}}
let _ = self.0.validate()?;
{{/vendorExtensions.is-nested}}
{{#vendorExtensions.is-string}}
let _ = check_xss_string(&self.0).map_err(from_validation_error)?;
{{/vendorExtensions.is-string}}
{{#vendorExtensions.is-vec-nested}}
for v in self.0.iter() {
let _ = v.validate()?;
}
{{/vendorExtensions.is-vec-nested}}
{{#vendorExtensions.is-vec-string}}
let _ = check_xss_vec_string(&self.0).map_err(from_validation_error)?;
{{/vendorExtensions.is-vec-string}}
{{#vendorExtensions.is-map-nested}}
let _ = check_xss_map_nested(&self.0).map_err(from_validation_error)?;
{{/vendorExtensions.is-map-nested}}
{{#vendorExtensions.is-map}}
let _ = check_xss_map(&self.0).map_err(from_validation_error)?;
{{/vendorExtensions.is-map}}
{{#vendorExtensions.is-map-string}}
let _ = check_xss_map_string(&self.0).map_err(from_validation_error)?;
{{/vendorExtensions.is-map-string}}
{{/isNullable}}
std::result::Result::Ok(())
}
}
@@ -630,7 +597,7 @@ impl std::convert::From<{{{dataType}}}> for {{{classname}}} {
impl std::fmt::Display for {{{classname}}} {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
write!(f, "{:?}", self.0)
}
}
@@ -689,7 +656,7 @@ impl ::std::str::FromStr for {{{classname}}} {
{{! vec}}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
pub struct {{{classname}}}(pub Vec<{{{arrayModelType}}}>);
pub struct {{{classname}}}(Vec<{{{arrayModelType}}}>);
impl validator::Validate for {{{classname}}} {
fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {

View File

@@ -11,6 +11,3 @@ use crate::{header, types::*};
#[allow(unused_imports)]
use crate::{apis, models};
#[allow(unused_imports)]
use crate::{models::check_xss_string, models::check_xss_vec_string, models::check_xss_map_string, models::check_xss_map_nested, models::check_xss_map};

View File

@@ -5,108 +5,67 @@
#[derive(validator::Validate)]
#[allow(dead_code)]
struct {{{operationIdCamelCase}}}BodyValidator<'a> {
{{^x-consumes-plain-text}}
{{#isModel}}
#[validate(nested)]
{{/isModel}}
{{^isModel}}
{{#hasValidation}}
#[validate(
{{#maxLength}}
{{#minLength}}
length(min = {{minLength}}, max = {{maxLength}}),
{{/minLength}}
{{^minLength}}
length(max = {{maxLength}}),
{{/minLength}}
{{/maxLength}}
{{^maxLength}}
{{#minLength}}
length(min = {{minLength}}),
{{/minLength}}
{{/maxLength}}
{{#pattern}}
{{#isString}}
regex(path = *RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.uppercase}}),
{{/isString}}
{{^isString}}
custom(function = "validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.lowercase}}"),
{{/isString}}
{{/pattern}}
{{#hasValidation}}
#[validate(
{{#maxLength}}
{{#minLength}}
length(min = {{minLength}}, max = {{maxLength}}),
{{/minLength}}
{{^minLength}}
length(max = {{maxLength}}),
{{/minLength}}
{{/maxLength}}
{{^maxLength}}
{{#minLength}}
length(min = {{minLength}}),
{{/minLength}}
{{/maxLength}}
{{#pattern}}
{{#isString}}
custom(function = "check_xss_string"),
regex(path = *RE_{{#lambda.uppercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.uppercase}}),
{{/isString}}
{{#maximum}}
{{#minimum}}
range(min = {{minimum}}, max = {{maximum}}),
{{/minimum}}
{{^minimum}}
range(max = {{maximum}}),
{{/minimum}}
{{/maximum}}
{{#minimum}}
{{^maximum}}
range(min = {{minimum}}),
{{/maximum}}
{{/minimum}}
{{#maxItems}}
{{#minItems}}
length(min = {{minItems}}, max = {{maxItems}}),
{{/minItems}}
{{^minItems}}
length(max = {{maxItems}}),
{{/minItems}}
{{/maxItems}}
{{^maxItems}}
{{#minItems}}
length(min = {{minItems}}),
{{/minItems}}
{{/maxItems}}
{{#vendorExtensions.is-vec-nested}}
nested,
{{/vendorExtensions.is-vec-nested}}
{{#vendorExtensions.is-vec-string}}
custom(function = "check_xss_vec_string"),
{{/vendorExtensions.is-vec-string}}
{{#vendorExtensions.is-map-nested}}
custom(function = "check_xss_map_nested"),
{{/vendorExtensions.is-map-nested}}
{{#vendorExtensions.is-map}}
custom(function = "check_xss_map"),
{{/vendorExtensions.is-map}}
{{#vendorExtensions.is-map-string}}
custom(function = "check_xss_map_string"),
{{/vendorExtensions.is-map-string}} )]
{{/hasValidation}}
{{^isString}}
custom(function = "validate_byte_{{#lambda.lowercase}}{{{operationIdCamelCase}}}BodyValidator{{/lambda.lowercase}}"),
{{/isString}}
{{/pattern}}
{{#maximum}}
{{#minimum}}
range(min = {{minimum}}, max = {{maximum}}),
{{/minimum}}
{{^minimum}}
range(max = {{maximum}}),
{{/minimum}}
{{/maximum}}
{{#minimum}}
{{^maximum}}
range(min = {{minimum}}),
{{/maximum}}
{{/minimum}}
{{#maxItems}}
{{#minItems}}
length(min = {{minItems}}, max = {{maxItems}}),
{{/minItems}}
{{^minItems}}
length(max = {{maxItems}}),
{{/minItems}}
{{/maxItems}}
{{^maxItems}}
{{#minItems}}
length(min = {{minItems}}),
{{/minItems}}
{{/maxItems}}
)]
{{/hasValidation}}
{{^x-consumes-plain-text}}
{{^hasValidation}}
{{#vendorExtensions.is-nested}}
#[validate(nested)]
{{/vendorExtensions.is-nested}}
{{#vendorExtensions.is-string}}
#[validate(custom(function = "check_xss_string"))]
{{/vendorExtensions.is-string}}
{{#vendorExtensions.is-vec-nested}}
#[validate(nested)]
{{/vendorExtensions.is-vec-nested}}
{{#vendorExtensions.is-vec-string}}
#[validate(custom(function = "check_xss_vec_string"))]
{{/vendorExtensions.is-vec-string}}
{{#vendorExtensions.is-map-nested}}
#[validate(custom(function = "check_xss_map_nested"))]
{{/vendorExtensions.is-map-nested}}
{{#vendorExtensions.is-map}}
#[validate(custom(function = "check_xss_map"))]
{{/vendorExtensions.is-map}}
{{#vendorExtensions.is-map-string}}
#[validate(custom(function = "check_xss_map_string"))]
{{/vendorExtensions.is-map-string}}
{{^isMap}}
#[validate(nested)]
{{/isMap}}
{{/hasValidation}}
{{/isModel}}
body: &'a {{{dataType}}},
{{/x-consumes-plain-text}}
{{#x-consumes-plain-text}}
{{#isString}}
#[validate(custom(function = "check_xss_string"))]
body: &'a String,
{{/isString}}
{{^isString}}

View File

@@ -5,7 +5,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[allow(dead_code)]
pub struct Object(pub serde_json::Value);
pub struct Object(serde_json::Value);
impl validator::Validate for Object {
fn validate(&self) -> Result<(), validator::ValidationErrors> {

View File

@@ -76,6 +76,8 @@ pub async fn create(addr: &str, https: bool) {
}
} else {
info!("Starting a server (over http, so no TLS)");
// Using HTTP
let listener = TcpListener::bind(&addr).await.unwrap();
println!("Listening on http://{}", addr);
loop {

View File

@@ -99,9 +99,6 @@ pub enum {{{operationIdCamelCase}}}Error {
{{#notes}}
/// {{{.}}}
{{/notes}}
{{#isDeprecated}}
#[deprecated]
{{/isDeprecated}}
{{#vendorExtensions.x-group-parameters}}
pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration: &configuration::Configuration{{#allParams}}{{#-first}}, {{!
### Params

View File

@@ -74,7 +74,6 @@ export class {{classname}} extends BaseService {
{{#notes}}
* {{.}}
{{/notes}}
* @endpoint {{httpMethod}} {{{path}}}
{{^useSingleRequestParameter}}
{{#allParams}}
* @param {{paramName}} {{description}}
@@ -303,7 +302,7 @@ export class {{classname}} extends BaseService {
headers: localVarHeaders,
observe: observe,
{{#httpTransferCacheInOptions}}
...(localVarTransferCache !== undefined ? { transferCache: localVarTransferCache } : {}),
transferCache: localVarTransferCache,
{{/httpTransferCacheInOptions}}
reportProgress: reportProgress
}

View File

@@ -38,7 +38,6 @@ export interface {{classname}}Interface {
/**
* {{summary}}
* {{notes}}
* @endpoint {{httpMethod}} {{{path}}}
{{^useSingleRequestParameter}}
{{#allParams}}* @param {{paramName}} {{description}}
{{/allParams}}{{/useSingleRequestParameter}}{{#useSingleRequestParameter}}{{#allParams.0}}* @param requestParameters

View File

@@ -17,7 +17,7 @@ import FormData from 'form-data'
{{/withNodeImports}}
// Some imports not used depending on template conditions
// @ts-ignore
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction{{#withAWSV4Signature}}, setAWS4SignatureInterceptor{{/withAWSV4Signature}} } from './common{{importFileExtension}}';
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common{{importFileExtension}}';
import type { RequestArgs } from './base{{importFileExtension}}';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base{{importFileExtension}}';

View File

@@ -17,7 +17,7 @@ import FormData from 'form-data'
{{/withNodeImports}}
// Some imports not used depending on template conditions
// @ts-ignore
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction{{#withAWSV4Signature}}, setAWS4SignatureInterceptor{{/withAWSV4Signature}} } from '{{apiRelativeToRoot}}common{{importFileExtension}}';
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '{{apiRelativeToRoot}}common{{importFileExtension}}';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '{{apiRelativeToRoot}}base{{importFileExtension}}';
{{#imports}}
@@ -71,10 +71,6 @@ export const {{classname}}AxiosParamCreator = function (configuration?: Configur
{{#authMethods}}
// authentication {{name}} required
{{#isApiKey}}
{{#withAWSV4Signature}}
// aws v4 signature authentication required
await setAWS4SignatureInterceptor(globalAxios, configuration)
{{/withAWSV4Signature}}
{{#isKeyInHeader}}
await setApiKeyToObject(localVarHeaderParameter, "{{keyParamName}}", configuration)
{{/isKeyInHeader}}

View File

@@ -2,12 +2,10 @@
/* eslint-disable */
{{>licenseInfo}}
import type { Configuration } from "./configuration{{importFileExtension}}";
import type { RequestArgs } from "./base{{importFileExtension}}";
import type { AxiosInstance, AxiosResponse } from 'axios';
{{#withAWSV4Signature}}
import { aws4Interceptor } from "aws4-axios";
{{/withAWSV4Signature}}
import { RequiredError } from "./base{{importFileExtension}}";
{{#withNodeImports}}
import { URL, URLSearchParams } from 'url';
@@ -58,25 +56,6 @@ export const setOAuthToObject = async function (object: any, name: string, scope
}
}
{{#withAWSV4Signature}}
export const setAWS4SignatureInterceptor = async function (globalAxios: AxiosInstance, configuration?: Configuration) {
if (configuration && configuration.awsv4) {
const interceptor = aws4Interceptor({
options: {
region: configuration.awsv4?.options?.region ?? process.env.AWS_REGION ?? 'us-east-1',
service: configuration.awsv4?.options?.service ?? 'execute-api',
},
credentials: {
accessKeyId: configuration.awsv4?.credentials?.accessKeyId ?? process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: configuration.awsv4?.credentials?.secretAccessKey ?? process.env.AWS_SECRET_ACCESS_KEY,
sessionToken: configuration.awsv4?.credentials?.sessionToken ?? process.env.AWS_SESSION_TOKEN
},
});
globalAxios.interceptors.request.use(interceptor);
}
}
{{/withAWSV4Signature}}
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
if (parameter == null) return;
if (typeof parameter === "object") {

View File

@@ -1,24 +1,13 @@
/* tslint:disable */
/* eslint-disable */
{{>licenseInfo}}
interface AWSv4Configuration {
options?: {
region?: string
service?: string
}
credentials?: {
accessKeyId?: string
secretAccessKey?: string,
sessionToken?: string
}
}
export interface ConfigurationParameters {
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
username?: string;
password?: string;
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
awsv4?: AWSv4Configuration;
basePath?: string;
serverIndex?: number;
baseOptions?: any;
@@ -45,17 +34,6 @@ export class Configuration {
* @param scopes oauth2 scope
*/
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
/**
* parameter for aws4 signature security
* @param {Object} AWS4Signature - AWS4 Signature security
* @param {string} options.region - aws region
* @param {string} options.service - name of the service.
* @param {string} credentials.accessKeyId - aws access key id
* @param {string} credentials.secretAccessKey - aws access key
* @param {string} credentials.sessionToken - aws session token
* @memberof Configuration
*/
awsv4?: AWSv4Configuration;
/**
* override base path
*/
@@ -82,7 +60,6 @@ export class Configuration {
this.username = param.username;
this.password = param.password;
this.accessToken = param.accessToken;
this.awsv4 = param.awsv4;
this.basePath = param.basePath;
this.serverIndex = param.serverIndex;
this.baseOptions = {

View File

@@ -27,9 +27,6 @@
},
"dependencies": {
"axios": "{{axiosVersion}}"
{{#withAWSV4Signature}}
"aws4-axios": "^3.3.4"
{{/withAWSV4Signature}}
},
"devDependencies": {
"@types/node": "12.11.5 - 12.20.42",

View File

@@ -1,127 +1,46 @@
# {{npmName}}@{{npmVersion}}
## {{npmName}}@{{npmVersion}}
A TypeScript SDK client for the {{host}} API.
This generator creates TypeScript/JavaScript client that utilizes [Fetch API](https://fetch.spec.whatwg.org/). The generated Node module can be used in the following environments:
## Usage
Environment
* Node.js
* Webpack
* Browserify
First, install the SDK from npm.
Language level
* ES5 - you must have a Promises/A+ library installed
* ES6
```bash
npm install {{npmName}} --save
```
Module system
* CommonJS
* ES6 module system
Next, try it out.
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}
```ts
{{>api_example}}
```
{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
## Documentation
### API Endpoints
All URIs are relative to *{{basePath}}*
| Class | Method | HTTP request | Description
| ----- | ------ | ------------ | -------------
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}/{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{summary}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
### Models
{{#models}}{{#model}}- [{{{classname}}}]({{modelDocPath}}/{{{classname}}}.md){{/model}}
{{/models}}
### Authorization
{{^authMethods}}Endpoints do not require authorization.{{/authMethods}}
{{#hasAuthMethods}}Authentication schemes defined for the API:{{/hasAuthMethods}}
{{#authMethods}}
<a id="{{name}}{{#isOAuth}}-{{flow}}{{/isOAuth}}"></a>
#### {{name}}{{#isOAuth}} {{flow}}{{/isOAuth}}
{{#isApiKey}}
- **Type**: API key
- **API key parameter name**: `{{keyParamName}}`
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
{{/isApiKey}}
{{#isBasicBasic}}
- **Type**: HTTP basic authentication
{{/isBasicBasic}}
{{#isBasicBearer}}
- **Type**: HTTP Bearer Token authentication{{#bearerFormat}} ({{{.}}}){{/bearerFormat}}
{{/isBasicBearer}}
{{#isHttpSignature}}
- **Type**: HTTP signature authentication
{{/isHttpSignature}}
{{#isOAuth}}
- **Type**: OAuth
- **Flow**: {{flow}}
- **Authorization URL**: {{authorizationUrl}}
- **Scopes**: {{^scopes}}N/A{{/scopes}}
{{#scopes}} - `{{scope}}`: {{description}}
{{/scopes}}
{{/isOAuth}}
{{/authMethods}}
## About
This TypeScript SDK client supports the [Fetch API](https://fetch.spec.whatwg.org/)
and is automatically generated by the
[OpenAPI Generator](https://openapi-generator.tech) project:
- API version: `{{appVersion}}`
- Package version: `{{npmVersion}}`
{{^hideGenerationTimestamp}}
- Build date: `{{generatedDate}}`
{{/hideGenerationTimestamp}}
- Generator version: `{{generatorVersion}}`
- Build package: `{{generatorClass}}`
The generated npm module supports the following:
- Environments
* Node.js
* Webpack
* Browserify
- Language levels
* ES5 - you must have a Promises/A+ library installed
* ES6
- Module systems
* CommonJS
* ES6 module system
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
## Development
It can be used in both TypeScript and JavaScript. In TypeScript, the definition will be automatically resolved via `package.json`. ([Reference](https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html))
### Building
To build the TypeScript source code, you need to have Node.js and npm installed.
After cloning the repository, navigate to the project directory and run:
```bash
To build and compile the typescript sources to javascript use:
```
npm install
npm run build
```
### Publishing
Once you've built the package, you can publish it to npm:
First build the package then run `npm publish`
```bash
npm publish
### Consuming
navigate to the folder of your consuming project and run one of the following commands.
_published:_
```
npm install {{npmName}}@{{npmVersion}} --save
```
## License
_unPublished (not recommended):_
[{{licenseInfo}}]({{{licenseUrl}}})
```
npm install PATH_TO_GENERATED_PACKAGE --save
```

View File

@@ -1,63 +0,0 @@
# {{classname}}{{#description}}
{{.}}{{/description}}
All URIs are relative to *{{basePath}}*
| Method | HTTP request | Description |
|------------- | ------------- | -------------|
{{#operations}}{{#operation}}| [**{{operationId}}**]({{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{commonPath}}{{path}} | {{summary}} |
{{/operation}}{{/operations}}
{{#operations}}
{{#operation}}
## {{operationId}}
> {{#returnType}}{{.}} {{/returnType}}{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
{{summary}}{{#notes}}
{{.}}{{/notes}}
### Example
```ts
{{>api_example}}
```
### Parameters
{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
| Name | Type | Description | Notes |
|------------- | ------------- | ------------- | -------------|{{/-last}}{{/allParams}}
{{#allParams}}| **{{paramName}}** | {{#isEnum}}{{#allowableValues}}{{#values}}`{{{.}}}`{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}{{/isEnum}}{{^isEnum}}{{#isModel}}[{{baseType}}]({{baseType}}.md){{/isModel}}{{^isModel}}`{{{dataType}}}`{{/isModel}}{{/isEnum}} | {{description}} |{{^required}} [Optional]{{/required}}{{^isContainer}}{{#defaultValue}} [Defaults to `{{.}}`]{{/defaultValue}}{{/isContainer}}{{#allowableValues}} [Enum: {{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}]{{/allowableValues}} |
{{/allParams}}
### Return type
{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{returnType}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}`void` (Empty response body){{/returnType}}
### Authorization
{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}{{#isOAuth}} {{flow}}{{/isOAuth}}](../README.md#{{{name}}}{{#isOAuth}}-{{flow}}{{/isOAuth}}){{^-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}} <br> {{/headers}}{{^headers.0}} - {{/headers.0}} |
{{/responses}}
{{/responses.0}}
[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)
{{/operation}}
{{/operations}}

View File

@@ -1,44 +0,0 @@
import {
Configuration,
{{classname}},
} from '{{npmName}}';
import type { {{operationIdCamelCase}}Request } from '{{npmName}}';
async function example() {
console.log("🚀 Testing {{npmName}} SDK...");
{{#hasAuthMethods}}
const config = new Configuration({ {{#authMethods}}{{#isBasicBasic}}
// To configure HTTP basic authorization: {{{name}}}
username: "YOUR USERNAME",
password: "YOUR PASSWORD",{{/isBasicBasic}}{{#isBasicBearer}}
// Configure HTTP bearer authorization: {{{name}}}
accessToken: "YOUR BEARER TOKEN",{{/isBasicBearer}}{{#isOAuth}}
// To configure OAuth2 access token for authorization: {{{name}}} {{{flow}}}
accessToken: "YOUR ACCESS TOKEN",{{/isOAuth}}{{#isApiKey}}
// To configure API key authorization: {{{name}}}
apiKey: "YOUR API KEY",{{/isApiKey}}{{#isHttpSignature}}
// To configure HTTP signature authorization: {{{name}}}
headers: { "YOUR HEADER NAME": "YOUR SIGNATURE" },{{/isHttpSignature}}{{/authMethods}}
});
{{/hasAuthMethods}}
const api = new {{classname}}({{#hasAuthMethods}}config{{/hasAuthMethods}});
{{#hasParams}}
const body = {
{{#allParams}}
// {{{dataType}}}{{#description}} | {{{description}}}{{/description}}{{^required}} (optional){{/required}}
{{paramName}}: {{{example}}}{{^example}}...{{/example}},
{{/allParams}}
} satisfies {{operationIdCamelCase}}Request;
{{/hasParams}}
try {
const data = await api.{{{operationId}}}({{#hasParams}}body{{/hasParams}});
console.log(data);
} catch (error) {
console.error(error);
}
}
// Run the test
example().catch(console.error);

View File

@@ -47,12 +47,6 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole
return {{modelName}}FromJSONTyped(json, ignoreDiscriminator);
}
{{/discriminator.mappedModels}}
{{#hasSelfReferencingDiscriminatorMapping}}
if (json['{{discriminator.propertyBaseName}}'] === '{{selfReferencingDiscriminatorMapping.mappingName}}') {
return {{selfReferencingDiscriminatorMapping.modelName}}FromJSONTyped(json, true);
}
{{/hasSelfReferencingDiscriminatorMapping}}
}
{{/discriminator}}
return {

View File

@@ -1,41 +0,0 @@
{{#models}}{{#model}}
# {{classname}}
{{#description}}{{&description}}
{{/description}}
## Properties
Name | Type
------------ | -------------
{{#vars}}`{{name}}` | {{#isPrimitiveType}}{{dataType}}{{/isPrimitiveType}}{{^isPrimitiveType}}[{{dataType}}]({{complexType}}.md){{/isPrimitiveType}}
{{/vars}}
{{^withoutRuntimeChecks}}
## Example
```typescript
import type { {{classname}} } from '{{npmName}}'
// TODO: Update the object below with actual values
const example = {
{{#vars}}
"{{name}}": {{{example}}},
{{/vars}}
} satisfies {{classname}}
console.log(example)
// Convert the instance to a JSON string
const exampleJSON: string = JSON.stringify(example)
console.log(exampleJSON)
// Parse the JSON string back to an object
const exampleParsed = JSON.parse(exampleJSON) as {{classname}}
console.log(exampleParsed)
```
{{/withoutRuntimeChecks}}
[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)
{{/model}}{{/models}}

View File

@@ -5036,19 +5036,6 @@ public class DefaultCodegenTest {
assertTrue(codegenOperation.queryParams.stream().allMatch(p -> p.queryIsJsonMimeType));
}
@Test
public void testDefaultOauthIsNotNull() {
final DefaultCodegen codegen = new DefaultCodegen();
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_1/issue_20662.yaml");
codegen.setOpenAPI(openAPI);
List<CodegenSecurity> securitySchemes = codegen.fromSecurity(openAPI.getComponents().getSecuritySchemes());
assertThat(securitySchemes.size()).isEqualTo(1);
CodegenSecurity openIdScheme = securitySchemes.get(0);
assertNotNull(openIdScheme.isOAuth);
assertFalse(openIdScheme.isOAuth);
assertTrue(openIdScheme.isOpenId);
}
private List<String> getRequiredVars(CodegenModel model) {
return getNames(model.getRequiredVars());
}

View File

@@ -1205,13 +1205,4 @@ public class InlineModelResolverTest {
assertNotNull(allOfRefWithDescriptionAndReadonly.getAllOf());
assertEquals(numberRangeRef, ((Schema) allOfRefWithDescriptionAndReadonly.getAllOf().get(0)).get$ref());
}
@Test
public void testNonNullTypeWithProperties() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/issue_21680_array_with_properties.yaml");
new InlineModelResolver().flatten(openAPI);
Schema<?> schema = (Schema<?>) openAPI.getComponents().getSchemas().get("errors");
assertNotNull(schema);
assertNull(schema.getProperties());
}
}

View File

@@ -17,7 +17,6 @@
package org.openapitools.codegen;
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.media.*;
import io.swagger.v3.oas.models.parameters.Parameter;
@@ -607,7 +606,8 @@ public class OpenAPINormalizerTest {
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(s.getExtensions().get(X_INTERNAL), true);
Map<String, String> options = Map.of("REMOVE_X_INTERNAL", "true");
Map<String, String> options = new HashMap<>();
options.put("REMOVE_X_INTERNAL", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
@@ -623,14 +623,34 @@ public class OpenAPINormalizerTest {
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = Map.of("FILTER", "operationId:delete|list");
Map<String, String> options = new HashMap<>();
options.put("FILTER", "operationId:delete|list");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
public void testOperationIdFilterWithTrim() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
options.put("FILTER", "operationId:\n\t\t\t\tdelete|\n\t\tlist");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
@@ -639,8 +659,10 @@ public class OpenAPINormalizerTest {
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = Map.of("FILTER", "method:get");
Map<String, String> options = new HashMap<>();
options.put("FILTER", "method:get");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
@@ -648,58 +670,22 @@ public class OpenAPINormalizerTest {
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
static OpenAPINormalizer.Filter parseFilter(String filters) {
OpenAPINormalizer.Filter filter = new OpenAPINormalizer.Filter(filters);
filter.parse();
return filter;
}
@Test
public void testFilterParsing() {
OpenAPINormalizer.Filter filter;
public void testFilterWithMethodWithTrim() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
// no filter
filter = parseFilter(" ");
assertFalse(filter.hasFilter());
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
// invalid filter
assertThrows(IllegalArgumentException.class, () ->
parseFilter("operationId:"));
Map<String, String> options = new HashMap<>();
options.put("FILTER", "method:\n\t\t\t\tget");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertThrows(IllegalArgumentException.class, () ->
parseFilter("invalid:invalid:"));
// extra spaces are trimmed
filter = parseFilter("method:\n\t\t\t\tget");
assertTrue(filter.hasFilter());
assertEquals(filter.methodFilters, Set.of("get"));
assertTrue(filter.operationIdFilters.isEmpty());
assertTrue(filter.tagFilters.isEmpty());
assertTrue(filter.pathStartingWithFilters.isEmpty());
// multiple values separated by pipe
filter = parseFilter("operationId:\n\t\t\t\tdelete|\n\t\tlist\t");
assertTrue(filter.hasFilter());
assertTrue(filter.methodFilters.isEmpty());
assertEquals(filter.operationIdFilters, Set.of("delete", "list"));
assertTrue(filter.tagFilters.isEmpty());
assertTrue(filter.pathStartingWithFilters.isEmpty());
// multiple filters
filter = parseFilter("operationId:delete|list;path:/v1");
assertTrue(filter.hasFilter());
assertTrue(filter.methodFilters.isEmpty());
assertEquals(filter.operationIdFilters, Set.of("delete", "list"));
assertTrue(filter.tagFilters.isEmpty());
assertEquals(filter.pathStartingWithFilters, Set.of("/v1"));
}
@Test
public void testMultiFilterParsing() {
OpenAPINormalizer.Filter filter = parseFilter("operationId: delete| list ; tag : testA |testB ");
assertEquals(filter.operationIdFilters, Set.of("delete", "list"));
assertEquals(filter.tagFilters, Set.of("testA", "testB"));
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
@@ -708,8 +694,10 @@ public class OpenAPINormalizerTest {
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = Map.of("FILTER", "tag:basic");
Map<String, String> options = new HashMap<>();
options.put("FILTER", "tag:basic");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
@@ -717,74 +705,24 @@ public class OpenAPINormalizerTest {
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
public void testCustomRoleFilter() {
public void testFilterWithTagWithTrim() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
Map<String, String> options = Map.of("FILTER", "role:admin");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options) {
@Override
protected Filter createFilter(OpenAPI openApi, String filters) {
return new CustomRoleFilter(filters);
}
};
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
options.put("FILTER", "tag:basic");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
private class CustomRoleFilter extends OpenAPINormalizer.Filter {
private Set<String> filteredRoles;
public CustomRoleFilter(String filters) {
super(filters);
}
@Override
protected void parse(String filterName, String filterValue) {
if ("role".equals(filterName)) {
this.filteredRoles = splitByPipe(filterValue);
} else {
parseFails(filterName, filterValue);
}
}
@Override
protected boolean hasCustomFilterMatch(String path, Operation operation) {
return operation.getExtensions() != null && filteredRoles.contains(operation.getExtensions().get("x-role"));
}
}
@Test
public void testFilterInvalidSyntaxDoesThrow() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
Map<String, String> options = Map.of("FILTER", "tag ; invalid");
try {
new OpenAPINormalizer(openAPI, options).normalize();
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "FILTER rule [tag ; invalid] must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3` or `path:/v1|/v2`. Error: filter with no value not supported :[tag]");
}
}
@Test
public void testFilterInvalidFilterDoesThrow() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
Map<String, String> options = Map.of("FILTER", "method:get ; unknown:test");
try {
new OpenAPINormalizer(openAPI, options).normalize();
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "FILTER rule [method:get ; unknown:test] must be in the form of `operationId:name1|name2|name3` or `method:get|post|put` or `tag:tag1|tag2|tag3` or `path:/v1|/v2`. Error: filter not supported :[unknown:test]");
}
}
@Test
public void testComposedSchemaDoesNotThrow() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/composed-schema.yaml");
@@ -1266,5 +1204,4 @@ public class OpenAPINormalizerTest {
return super.normalizeSchema(schema, visitedSchemas);
}
}
}

View File

@@ -368,27 +368,11 @@ public class CSharpModelTest {
public void nullablePropertyWithNullableReferenceTypesTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT)
.nullable(true))
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT).nullable(true))
.addProperties("urls", new ArraySchema()
.items(new StringSchema())
.nullable(true))
.items(new StringSchema()).nullable(true))
.addProperties("name", new StringSchema().nullable(true))
.addProperties("subObject", new Schema().addProperties("name", new StringSchema())
.nullable(true))
.addProperties("deepNullableAliasArray", new ArraySchema()
.items(new ArraySchema()
.items(new StringSchema()
.nullable(true))
.nullable(true))
.nullable(true))
.addProperties("deepAliasArray", new ArraySchema()
.items(new ArraySchema()
.items(new StringSchema())))
.addProperties("deepIntermediateNullableAliasArray", new ArraySchema()
.items(new ArraySchema()
.items(new StringSchema())
.nullable(true)))
.addProperties("subObject", new Schema().addProperties("name", new StringSchema()).nullable(true))
.addRequiredItem("id");
final DefaultCodegen codegen = new AspNetServerCodegen();
codegen.processOpts();
@@ -401,7 +385,7 @@ public class CSharpModelTest {
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 7);
Assert.assertEquals(cm.vars.size(), 4);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "id");
@@ -414,7 +398,7 @@ public class CSharpModelTest {
final CodegenProperty property2 = cm.vars.get(1);
Assert.assertEquals(property2.baseName, "urls");
Assert.assertEquals(property2.dataType, "List<string>");
Assert.assertEquals(property2.dataType, "List?<string>");
Assert.assertEquals(property2.name, "Urls");
Assert.assertNull(property2.defaultValue);
Assert.assertEquals(property2.baseType, "List?");
@@ -440,33 +424,6 @@ public class CSharpModelTest {
Assert.assertEquals(property4.baseType, "Object?");
Assert.assertFalse(property4.required);
Assert.assertFalse(property4.isPrimitiveType);
final CodegenProperty property5 = cm.vars.get(4);
Assert.assertEquals(property5.baseName, "deepNullableAliasArray");
Assert.assertEquals(property5.dataType, "List<List<string?>>");
Assert.assertEquals(property5.name, "DeepNullableAliasArray");
Assert.assertNull(property5.defaultValue);
Assert.assertEquals(property5.baseType, "List?");
Assert.assertEquals(property5.containerType, "array");
Assert.assertFalse(property5.required);
Assert.assertFalse(property5.isPrimitiveType);
Assert.assertTrue(property5.isContainer);
final CodegenProperty property6 = cm.vars.get(5);
Assert.assertEquals(property6.baseName, "deepAliasArray");
Assert.assertEquals(property6.dataType, "List<List<string>>");
Assert.assertEquals(property6.name, "DeepAliasArray");
Assert.assertEquals(property6.baseType, "List");
Assert.assertEquals(property6.containerType, "array");
Assert.assertTrue(property6.isContainer);
final CodegenProperty property7 = cm.vars.get(6);
Assert.assertEquals(property7.baseName, "deepIntermediateNullableAliasArray");
Assert.assertEquals(property7.dataType, "List<List<string>>");
Assert.assertEquals(property7.name, "DeepIntermediateNullableAliasArray");
Assert.assertEquals(property7.baseType, "List");
Assert.assertEquals(property7.containerType, "array");
Assert.assertTrue(property7.isContainer);
}
@Test(description = "convert a model with list property")

View File

@@ -50,7 +50,7 @@ public abstract class AbstractAnnotationsAssert<ACTUAL extends AbstractAnnotatio
return myself();
}
public ACTUAL containsWithNameAndDoesNotContainAttributes(final String name, final List<String> attributes) {
public ACTUAL containsWithNameAndDoesContainAttributes(final String name, final List<String> attributes) {
super
.withFailMessage("Should have annotation with name: " + name + " and no attributes: " + attributes + ", but was: " + actual)
.anyMatch(annotation -> annotation.getNameAsString().equals(name) && hasNotAttributes(annotation, attributes));

View File

@@ -1171,7 +1171,7 @@ public class SpringCodegenTest {
// Check that the @RequestMapping annotation is generated in the Api file
JavaFileAssert.assertThat(files.get("PetApi.java"))
.fileContains("@RequestMapping(\"${openapi.openAPIPetstore.base-path:/v2}\")",
"String PATH_ADD_PET = \"/pet\";",
"public static final String PATH_ADD_PET = \"/pet\";",
"value = PetApi.PATH_ADD_PET");
// Check that the @RequestMapping annotation is not generated in the Controller file
@@ -2272,12 +2272,8 @@ public class SpringCodegenTest {
additionalProperties.put(RETURN_SUCCESS_CODE, "true");
Map<String, File> files = generateFromContract("src/test/resources/bugs/issue_12524.json", SPRING_BOOT, additionalProperties);
// class extending array is no longer generated as it's automatically fixed by inline resolver
// by removing the properties for array type
//JavaFileAssert.assertThat(files.get("API01ListOfStuff.java"))
// .hasImports("com.fasterxml.jackson.annotation.JsonTypeName");
File notExisting = files.get("API01ListOfStuff.java");
assertThat(notExisting).isNull();
JavaFileAssert.assertThat(files.get("API01ListOfStuff.java"))
.hasImports("com.fasterxml.jackson.annotation.JsonTypeName");
} finally {
GlobalSettings.reset();
}
@@ -3763,22 +3759,22 @@ public class SpringCodegenTest {
.withType("JsonNullable<@Size(max = 1) String>")
.toType()
.assertProperty("intMinMaxNullable")
.withType("JsonNullable<@Min(value = 1) @Max(value = 10) Integer>")
.withType("JsonNullable<@Min(1) @Max(10) Integer>")
.toType()
.assertProperty("intMinNullable")
.withType("JsonNullable<@Min(value = 1) Integer>")
.withType("JsonNullable<@Min(1) Integer>")
.toType()
.assertProperty("intMaxNullable")
.withType("JsonNullable<@Max(value = 10) Integer>")
.withType("JsonNullable<@Max(10) Integer>")
.toType()
.assertProperty("numberMinMaxNullable")
.withType("JsonNullable<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>")
.toType()
.assertProperty("numberMinNullable")
.withType("JsonNullable<@DecimalMin(value = \"1\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(\"1\") BigDecimal>")
.toType()
.assertProperty("numberMaxNullable")
.withType("JsonNullable<@DecimalMax(value = \"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMax(\"10\") BigDecimal>")
.toType()
.assertProperty("stringDefaultNullable")
.withType("JsonNullable<@Size(max = 1) String>")
@@ -3867,12 +3863,12 @@ public class SpringCodegenTest {
assertJsonNullableMethod(javaFileAssert, String.class, "stringMinLengthNullable", "JsonNullable<@Size(min = 1) String>");
assertJsonNullableMethod(javaFileAssert, String.class, "stringMaxLengthNullable", "JsonNullable<@Size(max = 1) String>");
assertJsonNullableMethod(javaFileAssert, String.class, "stringEmailNullable", "JsonNullable<@jakarta.validation.constraints.Email String>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinMaxNullable", "JsonNullable<@Min(value = 1) @Max(value = 10) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinNullable", "JsonNullable<@Min(value = 1) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMaxNullable", "JsonNullable<@Max(value = 10) Integer>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinMaxNullable", "JsonNullable<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinNullable", "JsonNullable<@DecimalMin(value = \"1\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMaxNullable", "JsonNullable<@DecimalMax(value = \"10\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinMaxNullable", "JsonNullable<@Min(1) @Max(10) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinNullable", "JsonNullable<@Min(1) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMaxNullable", "JsonNullable<@Max(10) Integer>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinMaxNullable", "JsonNullable<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinNullable", "JsonNullable<@DecimalMin(\"1\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMaxNullable", "JsonNullable<@DecimalMax(\"10\") BigDecimal>");
}
@@ -3941,22 +3937,22 @@ public class SpringCodegenTest {
.withType("Optional<@jakarta.validation.constraints.Email String>")
.toType()
.assertProperty("intMinMax")
.withType("Optional<@Min(value = 1) @Max(value = 10) Integer>")
.withType("Optional<@Min(1) @Max(10) Integer>")
.toType()
.assertProperty("intMin")
.withType("Optional<@Min(value = 1) Integer>")
.withType("Optional<@Min(1) Integer>")
.toType()
.assertProperty("intMax")
.withType("Optional<@Max(value = 10) Integer>")
.withType("Optional<@Max(10) Integer>")
.toType()
.assertProperty("numberMinMax")
.withType("Optional<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>")
.withType("Optional<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>")
.toType()
.assertProperty("numberMin")
.withType("Optional<@DecimalMin(value = \"1\") BigDecimal>")
.withType("Optional<@DecimalMin(\"1\") BigDecimal>")
.toType()
.assertProperty("numberMax")
.withType("Optional<@DecimalMax(value = \"10\") BigDecimal>")
.withType("Optional<@DecimalMax(\"10\") BigDecimal>")
.toType()
.assertProperty("stringDefault")
.withType("Optional<@Size(max = 1) String>")
@@ -3979,22 +3975,22 @@ public class SpringCodegenTest {
.withType("JsonNullable<@Size(max = 1) String>")
.toType()
.assertProperty("intMinMaxNullable")
.withType("JsonNullable<@Min(value = 1) @Max(value = 10) Integer>")
.withType("JsonNullable<@Min(1) @Max(10) Integer>")
.toType()
.assertProperty("intMinNullable")
.withType("JsonNullable<@Min(value = 1) Integer>")
.withType("JsonNullable<@Min(1) Integer>")
.toType()
.assertProperty("intMaxNullable")
.withType("JsonNullable<@Max(value = 10) Integer>")
.withType("JsonNullable<@Max(10) Integer>")
.toType()
.assertProperty("numberMinMaxNullable")
.withType("JsonNullable<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>")
.toType()
.assertProperty("numberMinNullable")
.withType("JsonNullable<@DecimalMin(value = \"1\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(\"1\") BigDecimal>")
.toType()
.assertProperty("numberMaxNullable")
.withType("JsonNullable<@DecimalMax(value = \"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMax(\"10\") BigDecimal>")
.toType()
.assertProperty("stringDefaultNullable")
.withType("JsonNullable<@Size(max = 1) String>")
@@ -4070,12 +4066,12 @@ public class SpringCodegenTest {
assertOptionalMethod(javaFileAssert, String.class, "stringMinLength", "Optional<@Size(min = 1) String>");
assertOptionalMethod(javaFileAssert, String.class, "stringMaxLength", "Optional<@Size(max = 1) String>");
assertOptionalMethod(javaFileAssert, String.class, "stringEmail", "Optional<@jakarta.validation.constraints.Email String>");
assertOptionalMethod(javaFileAssert, Integer.class, "intMinMax", "Optional<@Min(value = 1) @Max(value = 10) Integer>");
assertOptionalMethod(javaFileAssert, Integer.class, "intMin", "Optional<@Min(value = 1) Integer>");
assertOptionalMethod(javaFileAssert, Integer.class, "intMax", "Optional<@Max(value = 10) Integer>");
assertOptionalMethod(javaFileAssert, BigDecimal.class, "numberMinMax", "Optional<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>");
assertOptionalMethod(javaFileAssert, BigDecimal.class, "numberMin", "Optional<@DecimalMin(value = \"1\") BigDecimal>");
assertOptionalMethod(javaFileAssert, BigDecimal.class, "numberMax", "Optional<@DecimalMax(value = \"10\") BigDecimal>");
assertOptionalMethod(javaFileAssert, Integer.class, "intMinMax", "Optional<@Min(1) @Max(10) Integer>");
assertOptionalMethod(javaFileAssert, Integer.class, "intMin", "Optional<@Min(1) Integer>");
assertOptionalMethod(javaFileAssert, Integer.class, "intMax", "Optional<@Max(10) Integer>");
assertOptionalMethod(javaFileAssert, BigDecimal.class, "numberMinMax", "Optional<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>");
assertOptionalMethod(javaFileAssert, BigDecimal.class, "numberMin", "Optional<@DecimalMin(\"1\") BigDecimal>");
assertOptionalMethod(javaFileAssert, BigDecimal.class, "numberMax", "Optional<@DecimalMax(\"10\") BigDecimal>");
assertOptionalMethod(javaFileAssert, "Zebra", "zebra", "Optional<Zebra>");
assertJsonNullableMethod(javaFileAssert, String.class, "stringPatternNullable", "JsonNullable<@Pattern(regexp = \"[a-z]\") String>");
@@ -4083,12 +4079,12 @@ public class SpringCodegenTest {
assertJsonNullableMethod(javaFileAssert, String.class, "stringMinLengthNullable", "JsonNullable<@Size(min = 1) String>");
assertJsonNullableMethod(javaFileAssert, String.class, "stringMaxLengthNullable", "JsonNullable<@Size(max = 1) String>");
assertJsonNullableMethod(javaFileAssert, String.class, "stringEmailNullable", "JsonNullable<@jakarta.validation.constraints.Email String>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinMaxNullable", "JsonNullable<@Min(value = 1) @Max(value = 10) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinNullable", "JsonNullable<@Min(value = 1) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMaxNullable", "JsonNullable<@Max(value = 10) Integer>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinMaxNullable", "JsonNullable<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinNullable", "JsonNullable<@DecimalMin(value = \"1\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMaxNullable", "JsonNullable<@DecimalMax(value = \"10\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinMaxNullable", "JsonNullable<@Min(1) @Max(10) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMinNullable", "JsonNullable<@Min(1) Integer>");
assertJsonNullableMethod(javaFileAssert, Integer.class, "intMaxNullable", "JsonNullable<@Max(10) Integer>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinMaxNullable", "JsonNullable<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMinNullable", "JsonNullable<@DecimalMin(\"1\") BigDecimal>");
assertJsonNullableMethod(javaFileAssert, BigDecimal.class, "numberMaxNullable", "JsonNullable<@DecimalMax(\"10\") BigDecimal>");
}
@@ -4816,7 +4812,7 @@ public class SpringCodegenTest {
// super(responseType, requestId, success, pageInfo);
// }
JavaFileAssert.assertThat(output.get("Object4.java"))
.assertConstructor("String", "String", "Boolean", "Type1")
.assertConstructor("Type1", "String", "String", "Boolean")
.hasParameter("responseType").toConstructor()
.hasParameter("requestId").toConstructor()
.hasParameter("success").toConstructor()
@@ -5762,319 +5758,7 @@ public class SpringCodegenTest {
.assertMethod("getNones")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("RequestMapping", List.of("version"));
}
@Test
public void testXSizeMessage_length() throws IOException {
final Map<String, File> files = generateFromContract("src/test/resources/3_0/error-message-for-size-max-min.yaml", SPRING_BOOT);
JavaFileAssert.assertThat(files.get("TestApi.java"))
.assertMethod("lengthTest")
.assertParameter("word")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 characters\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toParameter()
.toMethod()
.assertParameter("clientId")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 characters\""
));
JavaFileAssert.assertThat(files.get("LengthTest.java"))
.assertMethod("getField1")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 characters\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField2")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField3")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 characters\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField4")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Size", List.of("message"))
.toMethod()
.toFileAssert()
.assertMethod("getField5")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Size", List.of("message"))
.toMethod()
.toFileAssert()
.assertMethod("getField6")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Size", List.of("message"));
}
@Test
public void testXSizeMessage_size() throws IOException {
final Map<String, File> files = generateFromContract("src/test/resources/3_0/error-message-for-size-max-min.yaml", SPRING_BOOT);
JavaFileAssert.assertThat(files.get("TestApi.java"))
.assertMethod("sizeTest")
.assertParameter("values")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 elements\""
))
.toParameter()
.toMethod()
.assertParameter("tokens")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toParameter()
.toMethod()
.assertParameter("clientIds")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 elements\""
));
JavaFileAssert.assertThat(files.get("SizeTest.java"))
.assertMethod("getField1")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 elements\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField2")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField3")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Size", ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 elements\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField4")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Size", List.of("message"))
.toMethod()
.toFileAssert()
.assertMethod("getField5")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Size", List.of("message"))
.toMethod()
.toFileAssert()
.assertMethod("getField6")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Size", List.of("message"));
}
@Test
public void testXMinimumMessageAndXMaximumMessage_decimal() throws IOException {
final Map<String, File> files = generateFromContract("src/test/resources/3_0/error-message-for-size-max-min.yaml", SPRING_BOOT);
JavaFileAssert.assertThat(files.get("TestApi.java"))
.assertMethod("minmaxNumberTest")
.assertParameter("number")
.assertParameterAnnotations()
.containsWithNameAndAttributes("DecimalMin", ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("DecimalMax", ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotations()
.containsWithNameAndAttributes("DecimalMin", ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("DecimalMax", ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("clientNumber")
.assertParameterAnnotations()
.containsWithNameAndAttributes("DecimalMin", ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("DecimalMax", ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
));
JavaFileAssert.assertThat(files.get("NumberTest.java"))
.assertMethod("getField1")
.assertMethodAnnotations()
.containsWithNameAndAttributes("DecimalMin", ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("DecimalMax", ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField2")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("DecimalMin", List.of("message"))
.containsWithNameAndDoesNotContainAttributes("DecimalMax", List.of("message"));
}
@Test
public void testXMinimumMessageAndXMaximumMessage_integer() throws IOException {
final Map<String, File> files = generateFromContract("src/test/resources/3_0/error-message-for-size-max-min.yaml", SPRING_BOOT);
JavaFileAssert.assertThat(files.get("TestApi.java"))
.assertMethod("minmaxIntegerTest")
.assertParameter("number")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("clientNumber")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
));
JavaFileAssert.assertThat(files.get("IntegerTest.java"))
.assertMethod("getField1")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField2")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Min", List.of("message"))
.containsWithNameAndDoesNotContainAttributes("Max", List.of("message"));
}
@Test
public void testXMinimumMessageAndXMaximumMessage_long() throws IOException {
final Map<String, File> files = generateFromContract("src/test/resources/3_0/error-message-for-size-max-min.yaml", SPRING_BOOT);
JavaFileAssert.assertThat(files.get("TestApi.java"))
.assertMethod("minmaxLongTest")
.assertParameter("number")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("clientNumber")
.assertParameterAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
));
JavaFileAssert.assertThat(files.get("LongTest.java"))
.assertMethod("getField1")
.assertMethodAnnotations()
.containsWithNameAndAttributes("Min", ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.containsWithNameAndAttributes("Max", ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
))
.toMethod()
.toFileAssert()
.assertMethod("getField2")
.assertMethodAnnotations()
.containsWithNameAndDoesNotContainAttributes("Min", List.of("message"))
.containsWithNameAndDoesNotContainAttributes("Max", List.of("message"));
.containsWithNameAndDoesContainAttributes("RequestMapping", List.of("version"));
}
@Test

View File

@@ -1,45 +0,0 @@
package org.openapitools.codegen.kotlin.assertions;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@CanIgnoreReturnValue
abstract class AbstractAnnotationAssert<SELF extends AbstractAnnotationAssert<SELF>> extends AbstractAssert<SELF, KtAnnotationEntry> {
AbstractAnnotationAssert(final KtAnnotationEntry annotationEntry, final Class<?> selfType) {
super(annotationEntry, selfType);
}
public SELF hasAttributes(final Map<String, String> expectedAttributes) {
final Map<String, String> actualAttributes = actual.getValueArguments().stream()
.collect(Collectors.toMap(
a -> a.getArgumentName() != null ? a.getArgumentName().getAsName().asString() : null,
a -> a.getArgumentExpression() != null ? a.getArgumentExpression().getText() : null
));
final boolean allAttributesFound = expectedAttributes.entrySet().stream()
.allMatch(expected -> Objects.equals(actualAttributes.get(expected.getKey()), expected.getValue()));
Assertions.assertThat(allAttributesFound)
.withFailMessage("Expected annotation to have attributes %s, but has %s", expectedAttributes, actualAttributes)
.isTrue();
return myself;
}
public SELF hasNotAttributes(final List<String> notExpectedAttributes) {
final List<String> actualAttributes = actual.getValueArguments().stream()
.map(a -> a.getArgumentName() != null ? a.getArgumentName().getAsName().asString() : null)
.collect(Collectors.toList());
Assertions.assertThat(actualAttributes)
.withFailMessage("Expected annotation to not have attributes %s, but has %s", notExpectedAttributes, actualAttributes)
.noneMatch(notExpectedAttributes::contains);
return myself;
}
}

View File

@@ -1,51 +0,0 @@
package org.openapitools.codegen.kotlin.assertions;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtClass;
import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.psi.KtParameter;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@CanIgnoreReturnValue
public class ClassAssert extends AbstractAssert<ClassAssert, KtClass> {
private final KotlinFileAssert fileAssert;
ClassAssert(final KotlinFileAssert fileAssert, final KtClass actual) {
super(actual, ClassAssert.class);
this.fileAssert = fileAssert;
}
public MethodAssert assertMethod(final String methodName) {
Assertions.assertThat(actual.getBody())
.withFailMessage("Expected class to have a body, but it was null")
.isNotNull();
final List<KtNamedFunction> methods = actual.getBody().getFunctions().stream()
.filter(f -> Objects.equals(f.getName(), methodName))
.collect(Collectors.toList());
Assertions.assertThat(methods)
.withFailMessage("Expected class to have a single method %s, but found %s", methodName, methods.size())
.hasSize(1);
return new MethodAssert(this, methods.get(0));
}
public PrimaryConstructorParameterAssert assertPrimaryConstructorParameter(final String propertyName) {
final List<KtParameter> parameters = actual.getPrimaryConstructorParameters().stream()
.filter(p -> Objects.equals(p.getName(), propertyName))
.collect(Collectors.toList());
Assertions.assertThat(parameters)
.withFailMessage("Expected class to have a single property %s, but found %s", propertyName, parameters.size())
.hasSize(1);
return new PrimaryConstructorParameterAssert(this, parameters.get(0));
}
public KotlinFileAssert toFile() {
return fileAssert;
}
}

View File

@@ -1,52 +0,0 @@
package org.openapitools.codegen.kotlin.assertions;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer;
import org.jetbrains.kotlin.com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.kotlin.com.intellij.openapi.vfs.local.CoreLocalFileSystem;
import org.jetbrains.kotlin.com.intellij.psi.PsiManager;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.psi.KtClass;
import org.jetbrains.kotlin.psi.KtFile;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@CanIgnoreReturnValue
public class KotlinFileAssert extends AbstractAssert<KotlinFileAssert, KtFile> {
private KotlinFileAssert(final KtFile ktFile) {
super(ktFile, KotlinFileAssert.class);
}
public static KotlinFileAssert assertThat(final File file) {
final CompilerConfiguration config = new CompilerConfiguration();
config.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.Companion.getNONE());
final KotlinCoreEnvironment env = KotlinCoreEnvironment.createForProduction(Disposer.newDisposable(), config, EnvironmentConfigFiles.JVM_CONFIG_FILES);
final VirtualFile vFile = new CoreLocalFileSystem().findFileByIoFile(file);
Assertions.assertThat(vFile)
.withFailMessage("Expected file %s to exist but was not found", file.getAbsolutePath())
.isNotNull();
final KtFile ktFile = (KtFile) PsiManager.getInstance(env.getProject()).findFile(vFile);
return new KotlinFileAssert(ktFile);
}
public ClassAssert assertClass(final String className) {
final List<KtClass> ktClasses = Arrays.stream(actual.findChildrenByClass(KtClass.class))
.filter(clazz -> Objects.equals(clazz.getName(), className)).collect(Collectors.toList());
Assertions.assertThat(ktClasses)
.withFailMessage("Expected file to have single class %s, but found %s", className, ktClasses.size())
.hasSize(1);
return new ClassAssert(this, ktClasses.get(0));
}
}

View File

@@ -1,36 +0,0 @@
package org.openapitools.codegen.kotlin.assertions;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.psi.KtParameter;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@CanIgnoreReturnValue
public class MethodAssert extends AbstractAssert<MethodAssert, KtNamedFunction> {
private final ClassAssert classAssert;
MethodAssert(final ClassAssert classAssert, final KtNamedFunction method) {
super(method, MethodAssert.class);
this.classAssert = classAssert;
}
public ParameterAssert assertParameter(final String parameterName) {
final List<KtParameter> parameters = actual.getValueParameters().stream()
.filter(p -> Objects.equals(p.getName(), parameterName))
.collect(Collectors.toList());
Assertions.assertThat(parameters)
.withFailMessage("Expected class to have a single parameter %s, but found %s", parameterName, parameters.size())
.hasSize(1);
return new ParameterAssert(this, parameters.get(0));
}
public ClassAssert toClass() {
return classAssert;
}
}

View File

@@ -1,18 +0,0 @@
package org.openapitools.codegen.kotlin.assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
@CanIgnoreReturnValue
public class ParameterAnnotationAssert extends AbstractAnnotationAssert<ParameterAnnotationAssert> {
private final ParameterAssert parameterAssert;
ParameterAnnotationAssert(final ParameterAssert parameterAssert, final KtAnnotationEntry annotationEntry) {
super(annotationEntry, ParameterAnnotationAssert.class);
this.parameterAssert = parameterAssert;
}
public ParameterAssert toParameter() {
return parameterAssert;
}
}

View File

@@ -1,36 +0,0 @@
package org.openapitools.codegen.kotlin.assertions;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
import org.jetbrains.kotlin.psi.KtParameter;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@CanIgnoreReturnValue
public class ParameterAssert extends AbstractAssert<ParameterAssert, KtParameter> {
private final MethodAssert methodAssert;
ParameterAssert(final MethodAssert methodAssert, final KtParameter parameter) {
super(parameter, ParameterAssert.class);
this.methodAssert = methodAssert;
}
public ParameterAnnotationAssert assertParameterAnnotation(final String annotationName) {
final List<KtAnnotationEntry> annotations = actual.getAnnotationEntries().stream()
.filter(a -> Objects.equals(a.getShortName() != null ? a.getShortName().asString() : null, annotationName))
.collect(Collectors.toList());
Assertions.assertThat(annotations)
.withFailMessage("Expected parameter to have a single annotation %s, but found %s", annotationName, annotations.size())
.hasSize(1);
return new ParameterAnnotationAssert(this, annotations.get(0));
}
public MethodAssert toMethod() {
return methodAssert;
}
}

View File

@@ -1,18 +0,0 @@
package org.openapitools.codegen.kotlin.assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
@CanIgnoreReturnValue
public class PrimaryConstructorParameterAnnotationAssert extends AbstractAnnotationAssert<PrimaryConstructorParameterAnnotationAssert> {
private final PrimaryConstructorParameterAssert parameterAssert;
PrimaryConstructorParameterAnnotationAssert(final PrimaryConstructorParameterAssert parameterAssert, final KtAnnotationEntry annotationEntry) {
super(annotationEntry, PrimaryConstructorParameterAnnotationAssert.class);
this.parameterAssert = parameterAssert;
}
public PrimaryConstructorParameterAssert toPrimaryConstructorParameter() {
return parameterAssert;
}
}

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