Compare commits

...

25 Commits

Author SHA1 Message Date
William Cheng
e6f94c5d8b Auto fix invalid schemas in inline resolver 2025-10-21 15:13:26 +08:00
dependabot[bot]
816befc466 Bump vite and @angular-devkit/build-angular (#22192)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) to 6.4.1 and updates ancestor dependency [@angular-devkit/build-angular](https://github.com/angular/angular-cli). These dependencies need to be updated together.


Updates `vite` from 6.3.6 to 6.4.1
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@6.4.1/packages/vite)

Updates `@angular-devkit/build-angular` from 19.2.17 to 19.2.17
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/19.2.17...19.2.17)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.4.1
  dependency-type: indirect
- dependency-name: "@angular-devkit/build-angular"
  dependency-version: 19.2.17
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-21 15:08:27 +08:00
William Cheng
3d00fd2adc update C# samples 2025-10-21 11:40:43 +08:00
Fabian Buchenberger
00d16496c8 [csharp] do not use deprecated HttpRequestMessage.Properties (#20737) 2025-10-21 10:58:47 +08:00
William Cheng
57752d190c add cache: gradle to java setup workflow (#22183) 2025-10-20 17:15:36 +08:00
William Cheng
6572d5d9a6 Use JDK11 for kotlin-server projects (#22182)
* use jdk11 for kotlin server projects

* test with jdk11 by default
2025-10-20 16:54:50 +08:00
William Cheng
c15ba67fc9 update kotlin-spring projects to use jdk11 (#22181) 2025-10-20 15:48:10 +08:00
William Cheng
63ddce0c1b default REFACTOR_ALLOF_WITH_PROPERTIES_ONLY to true (#22180) 2025-10-20 11:39:09 +08:00
Kevin Liddle
01139e6963 [rust-axum] don't include quotes in output string from Display trait for string types (#22161)
* [rust-axum] don't include quotes in output string from Display trait for string types

* [rust-axum] update samples
2025-10-20 10:35:18 +08:00
Sven Allers
e7dae1a81e Custom error messages for size, length, min & max validations in Spring & Spring-Kotlin (#22090)
* Custom error messages for size, length, min & max validations in Spring & Spring-Kotlin

* Run scripts
2025-10-19 21:25:03 +08:00
Ilia
4e7bba659b [dart] Fix compile error in inline enum properties with "default" values(#22120) (#22165) 2025-10-19 20:47:20 +08:00
jpfinne
88bba259e9 OpenApiNormalizer FILTER improvements. Multi filters + filter on path (#22128)
* Use Filter Parser and allow multiple filters

* OpenAPINormalizer fails for invalid FILTER syntax

* Fix typo

* Use constants for filter keys.
Improve exception handling and tests.

* Fix format missing Locale.ROOT

* Make Filter extensible

* Additional unit test for invalid filter
2025-10-18 22:39:44 +08:00
William Cheng
8c85e3cedc [typescript-axios] Add support for AWSv4 Signature (#22174)
* [typescript-axios] Add support for AWSv4 Signature

* update typescript-axios.md file

* update doc

---------

Co-authored-by: qasim <qasim@calo.app>
2025-10-18 16:52:24 +08:00
Jérémy Reynard
d840c495c4 [FEAT] Support nullable Array<org.springframework.web.multipart.MultipartFile> in Kotlin-Spring generator (#21994)
* Support nullable `org.springframework.web.multipart.MultipartFile` in Kotlin Spring generator

- nullable is only supported for MultipartFile. However, Array<MultipartFile> could be also nullable

* Support nullable `org.springframework.web.multipart.MultipartFile` in Kotlin Spring generator

* Support nullable `org.springframework.web.multipart.MultipartFile` in Kotlin Spring generator

Update kotlin-spring-additionalproperties samples
2025-10-18 16:44:19 +08:00
Martin Tomašovič
7c000687e4 [csharp][generichost] Fix DateOnly parsing (#22099)
* Fix DateOnly parsing

* update samples
2025-10-18 14:58:36 +08:00
Mattias Sehlstedt
23a2aafe91 [CSHARP] Fix how the array type is set when using NULLABLE_REFERENCE_TYPES (#22071)
* Fix how the type is calculated for deep inline arrays

* Add list alias objects to petstore specification and regenerate samples
2025-10-18 14:58:08 +08:00
daberni
2afe7d29cd [Spring] Remove unnecessary modifiers from API interface templates (#22132)
* public static final String PATH_

* regenerate samples
2025-10-18 14:56:59 +08:00
William Cheng
6ede03d546 remove includeEndpointUrl (#22173) 2025-10-18 14:52:51 +08:00
Rostislav Svoboda
ee85775afd chore: Misc cleanup related to deprecations (#22172)
* Replace deprecated StringUtils.startsWith methods

* Add missing @Deprecated annotations
2025-10-18 14:52:19 +08:00
Robin Csutorás
94e8997cc7 [typescript-angular] Add includeEndpointUrl option to include endpoint URLs in generated service comments (#22152)
Adds a new boolean option 'includeEndpointUrl' that, when enabled, includes endpoint URL information as JSDoc comments in generated service methods and interfaces. This helps developers quickly identify the HTTP method and path for each API operation.

Co-authored-by: Robin Csutoras <robin.csutoras@Robins-Laptop.local>
2025-10-18 14:35:58 +08:00
jheyens
552ab4c6d5 Java-wiremock: Correctly handle multiple MIME-types in HTTP-Accept-headers (#22133)
* Java-wiremock: Allow matching multiple Accept-header values

* Wiremock: Ignore casing when matching requests' Content-Type headers

* Java-wiremock: Regenerate samples
2025-10-18 14:27:03 +08:00
daberni
2b00bab60a [Spring] Optimize and omit unnecessary imports on Api in ApiController templates (#22164)
* Optimize imports

* remove unnecessary blank line

* revert unintended indentation
2025-10-18 14:19:35 +08:00
Zach Hornback
ccd43a5ce4 [python-fastapi] Fix: Skip sorting of path operations (#22163) (#22166)
* [python-fastapi] Fix: Skip sorting of path operations (#22163)

Make use of helpful code added in
243f501aef to skip sorting of path
parameters.  In FastAPI, order matters, see link for details:
https://fastapi.tiangolo.com/tutorial/path-params/?h=path#order-matters

Issue: https://github.com/OpenAPITools/openapi-generator/issues/22163

* Update samples after previous commit

Reading comprehension is hard.  I missed the part of step 3 where
samples would be updated in response to the change I had previous
submitted.

Via this commit, update samples to match expectations.  The order of
various endpoint implementations is now changed in the sample, matchcing
the order in the yaml files that created them.
2025-10-18 14:18:15 +08:00
Rens Groothuijsen
592c262277 Set default value for isOauth field (#22162) 2025-10-17 15:49:26 +08:00
Bradford Hovinen
40b9d69d5a Support deprecated API endpoints in reqwest-based Rust clients (#22131)
Previously, if an API endpoint was marked deprecated, this fact was not
reflected in the generated Rust clients using the reqwest library. We
want to know exactly when our client code is using a deprecated endpoint,
so marking the corresponding functions with the `#[deprecatd]` attribute
would be very helpful. Uses of the endpoint would then be picked up by
linters so that we can react.

This adds a line to the template which marks functions generated from
deprecated endpoints with the `#[deprecated]` attribute.

This does not touch any of the other client generators for Rust or any
other language, since they are out of scope for our needs.

Co-authored-by: Bradford Hovinen <bho@qwello.eu>
2025-10-16 19:41:28 +08:00
718 changed files with 8503 additions and 5470 deletions

View File

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

View File

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

View File

@@ -27,6 +27,7 @@ jobs:
with:
distribution: 'temurin'
java-version: ${{ matrix.java }}
cache: gradle
- uses: actions/cache@v4
with:
@@ -95,6 +96,7 @@ 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,6 +21,7 @@ jobs:
with:
java-version: 11
distribution: 'temurin'
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:
@@ -59,6 +60,7 @@ jobs:
with:
java-version: 11
distribution: 'temurin'
cache: gradle
- name: Cache maven dependencies
uses: actions/cache@v4
env:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -538,6 +538,7 @@ 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)
@@ -645,7 +646,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.
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.
### Available Filters
@@ -658,6 +659,9 @@ 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
@@ -665,7 +669,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"
--openapi-normalizer FILTER="operationId:addPet|getPetById ; tag:store"
```
- `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,6 +3,7 @@ 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,6 +133,9 @@ 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,6 +67,9 @@ 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,6 +126,9 @@ 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,6 +44,7 @@ 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|
@@ -291,7 +292,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,6 +29,7 @@ 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;
@@ -248,7 +249,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 (!StringUtils.startsWith(relativePath, ".")) {
if (!Strings.CS.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 = false;
cs.isCode = cs.isPassword = cs.isApplication = cs.isImplicit = cs.isOpenId = cs.isOAuth = false;
cs.isHttpSignature = false;
cs.isBasicBasic = cs.isBasicBearer = false;
cs.scheme = securityScheme.getScheme();

View File

@@ -353,18 +353,22 @@ public class InlineModelResolver {
}
}
}
} 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;
} 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;
}
}
// 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 final Logger LOGGER = LoggerFactory.getLogger(OpenAPINormalizer.class);
protected static final Logger LOGGER = LoggerFactory.getLogger(OpenAPINormalizer.class);
Set<String> ruleNames = new TreeSet<>();
Set<String> rulesDefaultToTrue = new TreeSet<>();
@@ -133,10 +133,6 @@ 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";
@@ -215,6 +211,7 @@ 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);
@@ -275,30 +272,7 @@ public class OpenAPINormalizer {
if (inputRules.get(FILTER) != null) {
rules.put(FILTER, true);
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));
}
}
// actual parsing is delayed to allow customization of the Filter processing
}
if (inputRules.get(SET_CONTAINER_TO_NULLABLE) != null) {
@@ -344,6 +318,19 @@ 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.
@@ -405,15 +392,15 @@ public class OpenAPINormalizer {
"trace", PathItem::getTrace
);
// 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));
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);
}
});
}
// Include callback operation as well
for (Operation operation : path.readOperations()) {
@@ -430,22 +417,6 @@ 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());
@@ -1363,7 +1334,7 @@ public class OpenAPINormalizer {
*
* @param schema Schema to modify
* @param subSchemas List of sub-schemas to check
* @param schemaType Type of composed schema ("oneOf" or "anyOf")
* @param composedType Type of composed schema ("oneOf" or "anyOf")
* @return Simplified schema
*/
protected Schema simplifyComposedSchemaWithEnums(Schema schema, List<Object> subSchemas, String composedType) {
@@ -1832,4 +1803,164 @@ 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,6 +27,9 @@ 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

@@ -1628,7 +1628,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen {
Schema<?> target = ModelUtils.isGenerateAliasAsModel() ? p : schema;
if (ModelUtils.isArraySchema(target)) {
Schema<?> items = getSchemaItems(schema);
return getSchemaType(target) + "<" + getTypeDeclarationForArray(items) + ">";
return typeMapping.get("array") + "<" + getTypeDeclarationForArray(items) + ">";
} else if (ModelUtils.isMapSchema(p)) {
// Should we also support maps of maps?
Schema<?> inner = ModelUtils.getAdditionalProperties(p);

View File

@@ -34,6 +34,7 @@ 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;
@@ -601,7 +602,7 @@ public abstract class AbstractPythonConnexionServerCodegen extends AbstractPytho
@Override
public String toModelImport(String name) {
String modelImport;
if (StringUtils.startsWithAny(name, "import", "from")) {
if (Strings.CS.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -1012,6 +1012,9 @@ 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.StringUtils;
import org.apache.commons.lang3.Strings;
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 (StringUtils.startsWithAny(name, "import", "from")) {
if (Strings.CS.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -23,6 +23,7 @@ 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;
@@ -89,6 +90,11 @@ 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
@@ -198,7 +204,7 @@ public class PythonFastAPIServerCodegen extends AbstractPythonCodegen {
@Override
public String toModelImport(String name) {
String modelImport;
if (StringUtils.startsWithAny(name, "import", "from")) {
if (Strings.CS.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -20,6 +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;
@@ -353,7 +354,7 @@ public class PythonPydanticV1ClientCodegen extends AbstractPythonPydanticV1Codeg
@Override
public String toModelImport(String name) {
String modelImport;
if (StringUtils.startsWithAny(name, "import", "from")) {
if (Strings.CS.startsWithAny(name, "import", "from")) {
modelImport = name;
} else {
modelImport = "from ";

View File

@@ -1408,6 +1408,7 @@ 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,6 +1408,7 @@ 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,12 +568,8 @@ 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");
}
@@ -1217,6 +1213,9 @@ 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,6 +52,7 @@ 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;
@@ -60,6 +61,7 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
@Getter @Setter
protected String axiosVersion = DEFAULT_AXIOS_VERSION;
protected boolean withAWSV4Signature = false;
private String tsModelPackage = "";
@@ -71,7 +73,7 @@ public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodege
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.includeSecurityFeatures(SecurityFeature.BearerToken));
.includeSecurityFeatures(SecurityFeature.BearerToken, SecurityFeature.AWSV4Signature));
// clear import mapping (from default generator) as TS does not use it
// at the moment
@@ -94,6 +96,7 @@ 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);
}
@@ -182,6 +185,10 @@ 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);
}
@@ -307,6 +314,10 @@ 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

@@ -24,14 +24,16 @@ import io.swagger.v3.oas.annotations.media.ExampleObject;
{{#swagger1AnnotationLibrary}}
import io.swagger.annotations.*;
{{/swagger1AnnotationLibrary}}
{{#jdk8-no-delegate}}
{{^isDelegate}}
{{#jdk8-default-interface}}
{{#virtualService}}
import io.virtualan.annotation.ApiVirtual;
import io.virtualan.annotation.VirtualService;
{{/virtualService}}
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
{{/jdk8-no-delegate}}
{{/jdk8-default-interface}}
{{/isDelegate}}
{{^useResponseEntity}}
import org.springframework.http.HttpStatus;
{{/useResponseEntity}}
@@ -48,11 +50,13 @@ import org.springframework.web.bind.annotation.RestController;
{{/useResponseEntity}}
{{/useSpringController}}
import org.springframework.web.bind.annotation.*;
{{#jdk8-no-delegate}}
{{^reactive}}
{{#jdk8-default-interface}}
{{^isDelegate}}
{{^reactive}}
import org.springframework.web.context.request.NativeWebRequest;
{{/reactive}}
{{/jdk8-no-delegate}}
{{/reactive}}
{{/isDelegate}}
{{/jdk8-default-interface}}
import org.springframework.web.multipart.MultipartFile;
{{#reactive}}
import org.springframework.web.server.ServerWebExchange;
@@ -67,14 +71,14 @@ import {{javaxPackage}}.validation.constraints.*;
{{/useBeanValidation}}
import java.util.List;
import java.util.Map;
{{#jdk8-no-delegate}}
{{^isDelegate}}
import java.util.Optional;
{{/jdk8-no-delegate}}
{{^jdk8-no-delegate}}
{{/isDelegate}}
{{#isDelegate}}
{{#useOptional}}
import java.util.Optional;
{{/useOptional}}
{{/jdk8-no-delegate}}
{{/isDelegate}}
{{#async}}
import java.util.concurrent.CompletableFuture;
{{/async}}
@@ -128,7 +132,7 @@ public interface {{classname}} {
{{/jdk8-default-interface}}
{{#operation}}
public static final String PATH_{{#lambda.uppercase}}{{#lambda.snakecase}}{{{operationId}}}{{/lambda.snakecase}}{{/lambda.uppercase}} = "{{{path}}}";
String PATH_{{#lambda.uppercase}}{{#lambda.snakecase}}{{{operationId}}}{{/lambda.snakecase}}{{/lambda.uppercase}} = "{{{path}}}";
/**
* {{httpMethod}} {{{path}}}{{#summary}} : {{.}}{{/summary}}
{{#notes}}
@@ -261,7 +265,9 @@ 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}}) {{/maxLength}}{{/minLength}}{{!
}}{{#minLength}}{{#maxLength}}@Size(min = {{minLength}}, max = {{maxLength}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
minLength set, maxLength not
}}{{#minLength}}{{^maxLength}}@Size(min = {{minLength}}) {{/maxLength}}{{/minLength}}{{!
}}{{#minLength}}{{^maxLength}}@Size(min = {{minLength}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
minLength not set, maxLength set
}}{{^minLength}}{{#maxLength}}@Size(max = {{.}}) {{/maxLength}}{{/minLength}}{{!
}}{{^minLength}}{{#maxLength}}@Size(max = {{.}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxLength}}{{/minLength}}{{!
@Size: minItems && maxItems set
}}{{#minItems}}{{#maxItems}}@Size(min = {{minItems}}, max = {{maxItems}}) {{/maxItems}}{{/minItems}}{{!
}}{{#minItems}}{{#maxItems}}@Size(min = {{minItems}}, max = {{maxItems}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems set, maxItems not
}}{{#minItems}}{{^maxItems}}@Size(min = {{minItems}}) {{/maxItems}}{{/minItems}}{{!
}}{{#minItems}}{{^maxItems}}@Size(min = {{minItems}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems not set && maxItems set
}}{{^minItems}}{{#maxItems}}@Size(max = {{.}}) {{/maxItems}}{{/minItems}}{{!
}}{{^minItems}}{{#maxItems}}@Size(max = {{.}}{{#vendorExtensions.x-size-message}}, message = "{{vendorExtensions.x-size-message}}"{{/vendorExtensions.x-size-message}}) {{/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({{.}}) {{/minimum}}{{#maximum}}@Max({{.}}) {{/maximum}}{{/isInteger}}{{!
}}{{#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}}{{!
isLong set
}}{{#isLong}}{{#minimum}}@Min({{.}}L) {{/minimum}}{{#maximum}}@Max({{.}}L) {{/maximum}}{{/isLong}}{{!
}}{{#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}}{{!
Not Integer, not Long => we have a decimal value!
}}{{^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}}
}}{{^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}}

View File

@@ -167,6 +167,9 @@ 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;
@@ -382,12 +385,15 @@ 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;
@@ -474,9 +480,16 @@ 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.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out DateOnly result))
if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, 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.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out DateOnly result))
if (DateOnly.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, 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,7 +112,8 @@ 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());
@@ -191,6 +192,9 @@ 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;
@@ -283,7 +287,8 @@ namespace {{packageName}}.Client
/// </summary>
public void Dispose()
{
if(_disposeClient) {
if(_disposeClient)
{
_httpClient.Dispose();
}
}
@@ -413,7 +418,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;
@@ -424,7 +434,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)
@@ -459,7 +469,7 @@ namespace {{packageName}}.Client
transformed.Cookies.Add(cookie);
}
}
catch (PlatformNotSupportedException) {}
catch (PlatformNotSupportedException) { }
}
return transformed;
@@ -496,15 +506,22 @@ 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);
@@ -546,11 +563,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}}{{{defaultValue}}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{defaultValue}}}{{/isEnum}}{{/defaultValue}}{{/vendorExtensions.x-self-and-ancestor-only-props}};
..{{{name}}} = {{#isEnum}}{{^isContainer}}{{#enumName}}{{enumName}}.valueOf({{{defaultValue}}}){{/enumName}}{{^enumName}}{{{defaultValue}}}{{/enumName}}{{/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}};
{{^jdk8-no-delegate}}
{{^isDelegate}}
{{#imports}}import {{import}};
{{/imports}}
@@ -8,9 +8,9 @@ import io.swagger.annotations.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
{{/jdk8-no-delegate}}
{{/isDelegate}}
import org.springframework.stereotype.Controller;
{{^jdk8-no-delegate}}
{{^isDelegate}}
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}}
{{/jdk8-no-delegate}}
{{/isDelegate}}
{{^useSpringCloudClient}}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
@@ -60,7 +60,7 @@ public class {{classname}}Controller implements {{classname}} {
}
{{/isDelegate}}
{{^jdk8-no-delegate}}
{{^isDelegate}}
{{#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}}
{{/jdk8-no-delegate}}
{{/isDelegate}}
}
{{/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}}
.withHeader("Accept", havingExactly({{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}})){{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly("{{#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}}{{#produces}}
.withHeader("Accept", containing("{{{mediaType}}}")){{/produces}}{{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly(equalToIgnoreCase("{{#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}}
.withHeader("Accept", havingExactly({{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}})){{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly("{{#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}}{{#produces}}
.withHeader("Accept", containing("{{{mediaType}}}")){{/produces}}{{/hasProduces}}{{#hasAuthMethods}}{{#hasConsumes}}
.withHeader("Content-Type", havingExactly(equalToIgnoreCase("{{#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 = 1.8
sourceCompatibility = 11
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.jvmTarget = "11"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.jvmTarget = "11"
}
repositories {

View File

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

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

View File

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

View File

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

View File

@@ -69,7 +69,7 @@
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
<jvmTarget>11</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}}{{^isArray}}{{^required}}?{{/required}}{{/isArray}}{{/isFile}}
{{^isFile}}{{{dataType}}}{{^required}}{{^defaultValue}}?{{/defaultValue}}{{/required}}{{/isFile}}{{#isFile}}{{#isArray}}Array<{{/isArray}}org.springframework.web.multipart.MultipartFile{{#isArray}}>{{/isArray}}{{#isNullable}}?{{/isNullable}}{{/isFile}}

View File

@@ -630,7 +630,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)
}
}

View File

@@ -99,6 +99,9 @@ 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,6 +74,7 @@ export class {{classname}} extends BaseService {
{{#notes}}
* {{.}}
{{/notes}}
* @endpoint {{httpMethod}} {{{path}}}
{{^useSingleRequestParameter}}
{{#allParams}}
* @param {{paramName}} {{description}}

View File

@@ -38,6 +38,7 @@ 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 } from './common{{importFileExtension}}';
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction{{#withAWSV4Signature}}, setAWS4SignatureInterceptor{{/withAWSV4Signature}} } 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 } from '{{apiRelativeToRoot}}common{{importFileExtension}}';
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction{{#withAWSV4Signature}}, setAWS4SignatureInterceptor{{/withAWSV4Signature}} } from '{{apiRelativeToRoot}}common{{importFileExtension}}';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '{{apiRelativeToRoot}}base{{importFileExtension}}';
{{#imports}}
@@ -71,6 +71,10 @@ 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,10 +2,12 @@
/* 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';
@@ -56,6 +58,25 @@ 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,13 +1,24 @@
/* 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;
@@ -34,6 +45,17 @@ 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
*/
@@ -60,6 +82,7 @@ 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,6 +27,9 @@
},
"dependencies": {
"axios": "{{axiosVersion}}"
{{#withAWSV4Signature}}
"aws4-axios": "^3.3.4"
{{/withAWSV4Signature}}
},
"devDependencies": {
"@types/node": "12.11.5 - 12.20.42",

View File

@@ -5036,6 +5036,19 @@ 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,4 +1205,13 @@ 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,6 +17,7 @@
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;
@@ -606,8 +607,7 @@ 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 = new HashMap<>();
options.put("REMOVE_X_INTERNAL", "true");
Map<String, String> options = Map.of("REMOVE_X_INTERNAL", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
@@ -623,34 +623,14 @@ 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 = new HashMap<>();
options.put("FILTER", "operationId:delete|list");
Map<String, String> options = Map.of("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);
}
@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);
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
@@ -659,10 +639,8 @@ 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 = new HashMap<>();
options.put("FILTER", "method:get");
Map<String, String> options = Map.of("FILTER", "method:get");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
@@ -670,22 +648,58 @@ 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 testFilterWithMethodWithTrim() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
public void testFilterParsing() {
OpenAPINormalizer.Filter filter;
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);
// no filter
filter = parseFilter(" ");
assertFalse(filter.hasFilter());
Map<String, String> options = new HashMap<>();
options.put("FILTER", "method:\n\t\t\t\tget");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
// invalid filter
assertThrows(IllegalArgumentException.class, () ->
parseFilter("operationId:"));
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);
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"));
}
@Test
@@ -694,10 +708,8 @@ 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 = new HashMap<>();
options.put("FILTER", "tag:basic");
Map<String, String> options = Map.of("FILTER", "tag:basic");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
@@ -705,24 +717,74 @@ 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 testFilterWithTagWithTrim() {
public void testCustomRoleFilter() {
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", "tag:basic");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
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);
}
};
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), true);
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);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), false);
}
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");
@@ -1204,4 +1266,5 @@ public class OpenAPINormalizerTest {
return super.normalizeSchema(schema, visitedSchemas);
}
}
}

View File

@@ -368,11 +368,27 @@ 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("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)))
.addRequiredItem("id");
final DefaultCodegen codegen = new AspNetServerCodegen();
codegen.processOpts();
@@ -385,7 +401,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(), 4);
Assert.assertEquals(cm.vars.size(), 7);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "id");
@@ -398,7 +414,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?");
@@ -424,6 +440,33 @@ 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 containsWithNameAndDoesContainAttributes(final String name, final List<String> attributes) {
public ACTUAL containsWithNameAndDoesNotContainAttributes(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}\")",
"public static final String PATH_ADD_PET = \"/pet\";",
"String PATH_ADD_PET = \"/pet\";",
"value = PetApi.PATH_ADD_PET");
// Check that the @RequestMapping annotation is not generated in the Controller file
@@ -2272,8 +2272,12 @@ public class SpringCodegenTest {
additionalProperties.put(RETURN_SUCCESS_CODE, "true");
Map<String, File> files = generateFromContract("src/test/resources/bugs/issue_12524.json", SPRING_BOOT, additionalProperties);
JavaFileAssert.assertThat(files.get("API01ListOfStuff.java"))
.hasImports("com.fasterxml.jackson.annotation.JsonTypeName");
// 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();
} finally {
GlobalSettings.reset();
}
@@ -3759,22 +3763,22 @@ public class SpringCodegenTest {
.withType("JsonNullable<@Size(max = 1) String>")
.toType()
.assertProperty("intMinMaxNullable")
.withType("JsonNullable<@Min(1) @Max(10) Integer>")
.withType("JsonNullable<@Min(value = 1) @Max(value = 10) Integer>")
.toType()
.assertProperty("intMinNullable")
.withType("JsonNullable<@Min(1) Integer>")
.withType("JsonNullable<@Min(value = 1) Integer>")
.toType()
.assertProperty("intMaxNullable")
.withType("JsonNullable<@Max(10) Integer>")
.withType("JsonNullable<@Max(value = 10) Integer>")
.toType()
.assertProperty("numberMinMaxNullable")
.withType("JsonNullable<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>")
.toType()
.assertProperty("numberMinNullable")
.withType("JsonNullable<@DecimalMin(\"1\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(value = \"1\") BigDecimal>")
.toType()
.assertProperty("numberMaxNullable")
.withType("JsonNullable<@DecimalMax(\"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMax(value = \"10\") BigDecimal>")
.toType()
.assertProperty("stringDefaultNullable")
.withType("JsonNullable<@Size(max = 1) String>")
@@ -3863,12 +3867,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(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>");
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>");
}
@@ -3937,22 +3941,22 @@ public class SpringCodegenTest {
.withType("Optional<@jakarta.validation.constraints.Email String>")
.toType()
.assertProperty("intMinMax")
.withType("Optional<@Min(1) @Max(10) Integer>")
.withType("Optional<@Min(value = 1) @Max(value = 10) Integer>")
.toType()
.assertProperty("intMin")
.withType("Optional<@Min(1) Integer>")
.withType("Optional<@Min(value = 1) Integer>")
.toType()
.assertProperty("intMax")
.withType("Optional<@Max(10) Integer>")
.withType("Optional<@Max(value = 10) Integer>")
.toType()
.assertProperty("numberMinMax")
.withType("Optional<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>")
.withType("Optional<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>")
.toType()
.assertProperty("numberMin")
.withType("Optional<@DecimalMin(\"1\") BigDecimal>")
.withType("Optional<@DecimalMin(value = \"1\") BigDecimal>")
.toType()
.assertProperty("numberMax")
.withType("Optional<@DecimalMax(\"10\") BigDecimal>")
.withType("Optional<@DecimalMax(value = \"10\") BigDecimal>")
.toType()
.assertProperty("stringDefault")
.withType("Optional<@Size(max = 1) String>")
@@ -3975,22 +3979,22 @@ public class SpringCodegenTest {
.withType("JsonNullable<@Size(max = 1) String>")
.toType()
.assertProperty("intMinMaxNullable")
.withType("JsonNullable<@Min(1) @Max(10) Integer>")
.withType("JsonNullable<@Min(value = 1) @Max(value = 10) Integer>")
.toType()
.assertProperty("intMinNullable")
.withType("JsonNullable<@Min(1) Integer>")
.withType("JsonNullable<@Min(value = 1) Integer>")
.toType()
.assertProperty("intMaxNullable")
.withType("JsonNullable<@Max(10) Integer>")
.withType("JsonNullable<@Max(value = 10) Integer>")
.toType()
.assertProperty("numberMinMaxNullable")
.withType("JsonNullable<@DecimalMin(\"1\") @DecimalMax(\"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(value = \"1\") @DecimalMax(value = \"10\") BigDecimal>")
.toType()
.assertProperty("numberMinNullable")
.withType("JsonNullable<@DecimalMin(\"1\") BigDecimal>")
.withType("JsonNullable<@DecimalMin(value = \"1\") BigDecimal>")
.toType()
.assertProperty("numberMaxNullable")
.withType("JsonNullable<@DecimalMax(\"10\") BigDecimal>")
.withType("JsonNullable<@DecimalMax(value = \"10\") BigDecimal>")
.toType()
.assertProperty("stringDefaultNullable")
.withType("JsonNullable<@Size(max = 1) String>")
@@ -4066,12 +4070,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(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, 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, "Zebra", "zebra", "Optional<Zebra>");
assertJsonNullableMethod(javaFileAssert, String.class, "stringPatternNullable", "JsonNullable<@Pattern(regexp = \"[a-z]\") String>");
@@ -4079,12 +4083,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(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>");
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>");
}
@@ -4812,7 +4816,7 @@ public class SpringCodegenTest {
// super(responseType, requestId, success, pageInfo);
// }
JavaFileAssert.assertThat(output.get("Object4.java"))
.assertConstructor("Type1", "String", "String", "Boolean")
.assertConstructor("String", "String", "Boolean", "Type1")
.hasParameter("responseType").toConstructor()
.hasParameter("requestId").toConstructor()
.hasParameter("success").toConstructor()
@@ -5758,7 +5762,319 @@ public class SpringCodegenTest {
.assertMethod("getNones")
.assertMethodAnnotations()
.containsWithNameAndDoesContainAttributes("RequestMapping", List.of("version"));
.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"));
}
@Test

View File

@@ -0,0 +1,45 @@
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

@@ -0,0 +1,51 @@
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

@@ -0,0 +1,52 @@
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

@@ -0,0 +1,36 @@
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

@@ -0,0 +1,18 @@
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

@@ -0,0 +1,36 @@
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

@@ -0,0 +1,18 @@
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;
}
}

View File

@@ -0,0 +1,38 @@
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 PrimaryConstructorParameterAssert extends AbstractAssert<PrimaryConstructorParameterAssert, KtParameter> {
private final ClassAssert classAssert;
PrimaryConstructorParameterAssert(final ClassAssert classAssert, final KtParameter parameter) {
super(parameter, PrimaryConstructorParameterAssert.class);
this.classAssert = classAssert;
}
public PrimaryConstructorParameterAnnotationAssert assertParameterAnnotation(final String annotationName, final String useSiteTarget) {
final List<KtAnnotationEntry> annotations = actual.getAnnotationEntries().stream()
.filter(a ->
Objects.equals(a.getShortName() != null ? a.getShortName().asString() : null, annotationName)
&& Objects.equals(a.getUseSiteTarget() != null ? a.getUseSiteTarget().getText() : null, useSiteTarget))
.collect(Collectors.toList());
Assertions.assertThat(annotations)
.withFailMessage("Expected property to have a single annotation %s, but found %s", annotationName, annotations.size())
.hasSize(1);
return new PrimaryConstructorParameterAnnotationAssert(this, annotations.get(0));
}
public ClassAssert toClass() {
return classAssert;
}
}

View File

@@ -1,5 +1,6 @@
package org.openapitools.codegen.kotlin.spring;
import com.google.common.collect.ImmutableMap;
import io.swagger.parser.OpenAPIParser;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
@@ -17,6 +18,7 @@ import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.kotlin.KotlinTestUtils;
import org.openapitools.codegen.kotlin.assertions.KotlinFileAssert;
import org.openapitools.codegen.languages.KotlinSpringServerCodegen;
import org.openapitools.codegen.languages.features.CXFServerFeatures;
import org.openapitools.codegen.languages.features.DocumentationProviderFeatures;
@@ -370,6 +372,44 @@ public class KotlinSpringServerCodegenTest {
"ApiUtil");
}
@Test
public void testNullableMultipartFile() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
String outputPath = output.getAbsolutePath().replace('\\', '/');
OpenAPI openAPI = new OpenAPIParser()
.readLocation("src/test/resources/3_0/kotlin/feat-multipartfile_nullable.yaml", null, new ParseOptions()).getOpenAPI();
KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen();
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true");
ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);
DefaultGenerator generator = new DefaultGenerator();
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
generator.opts(input).generate();
assertFileContains(Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/NullableMultipartfileApiController.kt"),
"file: org.springframework.web.multipart.MultipartFile?)");
assertFileContains(Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/NullableMultipartfileArrayApiController.kt"),
"files: Array<org.springframework.web.multipart.MultipartFile>?)");
assertFileContains(Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/NonNullableMultipartfileApiController.kt"),
"file: org.springframework.web.multipart.MultipartFile)");
assertFileContains(Paths.get(outputPath + "/src/main/kotlin/org/openapitools/api/NonNullableMultipartfileArrayApiController.kt"),
"files: Array<org.springframework.web.multipart.MultipartFile>)");
}
@Test
public void arrayItemsCanBeNullable() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
@@ -752,7 +792,7 @@ public class KotlinSpringServerCodegenTest {
assertFileContains(
Paths.get(files.get("AddApi.kt").getAbsolutePath()),
"@Min(2)"
"@Min(value=2)"
);
}
@@ -1377,6 +1417,358 @@ public class KotlinSpringServerCodegenTest {
});
}
@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");
KotlinFileAssert.assertThat(files.get("TestApiController.kt"))
.assertClass("TestApiController")
.assertMethod("lengthTest")
.assertParameter("word")
.assertParameterAnnotation("Size")
.hasAttributes(ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 characters\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotation("Size")
.hasAttributes(ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toParameter()
.toMethod()
.assertParameter("clientId")
.assertParameterAnnotation("Size")
.hasAttributes(ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 characters\""
));
KotlinFileAssert.assertThat(files.get("LengthTest.kt"))
.assertClass("LengthTest")
.assertPrimaryConstructorParameter("field1")
.assertParameterAnnotation("Size", "get")
.hasAttributes(ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 characters\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field2")
.assertParameterAnnotation("Size", "get")
.hasAttributes(ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field3")
.assertParameterAnnotation("Size", "get")
.hasAttributes(ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 characters\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field4")
.assertParameterAnnotation("Size", "get")
.hasNotAttributes(List.of("message"))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field5")
.assertParameterAnnotation("Size", "get")
.hasNotAttributes(List.of("message"))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field6")
.assertParameterAnnotation("Size", "get")
.hasNotAttributes(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");
KotlinFileAssert.assertThat(files.get("TestApiController.kt"))
.assertClass("TestApiController")
.assertMethod("sizeTest")
.assertParameter("values")
.assertParameterAnnotation("Size")
.hasAttributes(ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 elements\""
))
.toParameter()
.toMethod()
.assertParameter("tokens")
.assertParameterAnnotation("Size")
.hasAttributes(ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toParameter()
.toMethod()
.assertParameter("clientIds")
.assertParameterAnnotation("Size")
.hasAttributes(ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 elements\""
));
KotlinFileAssert.assertThat(files.get("SizeTest.kt"))
.assertClass("SizeTest")
.assertPrimaryConstructorParameter("field1")
.assertParameterAnnotation("Size", "get")
.hasAttributes(ImmutableMap.of(
"max", "10",
"message", "\"Must be max 10 elements\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field2")
.assertParameterAnnotation("Size", "get")
.hasAttributes(ImmutableMap.of(
"min", "1",
"message", "\"Must not be empty\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field3")
.assertParameterAnnotation("Size", "get")
.hasAttributes(ImmutableMap.of(
"min", "3",
"max", "5",
"message", "\"Must be between 3 and 5 elements\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field4")
.assertParameterAnnotation("Size", "get")
.hasNotAttributes(List.of("message"))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field5")
.assertParameterAnnotation("Size", "get")
.hasNotAttributes(List.of("message"))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field6")
.assertParameterAnnotation("Size", "get")
.hasNotAttributes(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");
KotlinFileAssert.assertThat(files.get("TestApiController.kt"))
.assertClass("TestApiController")
.assertMethod("minmaxNumberTest")
.assertParameter("number")
.assertParameterAnnotation("DecimalMin")
.hasAttributes(ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("DecimalMax")
.hasAttributes(ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotation("DecimalMin")
.hasAttributes(ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("DecimalMax")
.hasAttributes(ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("clientNumber")
.assertParameterAnnotation("DecimalMin")
.hasAttributes(ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("DecimalMax")
.hasAttributes(ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
));
KotlinFileAssert.assertThat(files.get("NumberTest.kt"))
.assertClass("NumberTest")
.assertPrimaryConstructorParameter("field1")
.assertParameterAnnotation("DecimalMin", "get")
.hasAttributes(ImmutableMap.of(
"value", "\"0.1\"",
"message", "\"Must be positive\""
))
.toPrimaryConstructorParameter()
.assertParameterAnnotation("DecimalMax", "get")
.hasAttributes(ImmutableMap.of(
"value", "\"99.9\"",
"message", "\"Must be less than 100\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field2")
.assertParameterAnnotation("DecimalMin", "get")
.hasNotAttributes(List.of("message"))
.toPrimaryConstructorParameter()
.assertParameterAnnotation("DecimalMax", "get")
.hasNotAttributes(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");
KotlinFileAssert.assertThat(files.get("TestApiController.kt"))
.assertClass("TestApiController")
.assertMethod("minmaxIntegerTest")
.assertParameter("number")
.assertParameterAnnotation("Min")
.hasAttributes(ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("Max")
.hasAttributes(ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotation("Min")
.hasAttributes(ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("Max")
.hasAttributes(ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("clientNumber")
.assertParameterAnnotation("Min")
.hasAttributes(ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("Max")
.hasAttributes(ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
));
KotlinFileAssert.assertThat(files.get("IntegerTest.kt"))
.assertClass("IntegerTest")
.assertPrimaryConstructorParameter("field1")
.assertParameterAnnotation("Min", "get")
.hasAttributes(ImmutableMap.of(
"value", "1",
"message", "\"Must be positive\""
))
.toPrimaryConstructorParameter()
.assertParameterAnnotation("Max", "get")
.hasAttributes(ImmutableMap.of(
"value", "99",
"message", "\"Must be less than 100\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field2")
.assertParameterAnnotation("Min", "get")
.hasNotAttributes(List.of("message"))
.toPrimaryConstructorParameter()
.assertParameterAnnotation("Max", "get")
.hasNotAttributes(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");
KotlinFileAssert.assertThat(files.get("TestApiController.kt"))
.assertClass("TestApiController")
.assertMethod("minmaxLongTest")
.assertParameter("number")
.assertParameterAnnotation("Min")
.hasAttributes(ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("Max")
.hasAttributes(ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("token")
.assertParameterAnnotation("Min")
.hasAttributes(ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("Max")
.hasAttributes(ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
))
.toParameter()
.toMethod()
.assertParameter("clientNumber")
.assertParameterAnnotation("Min")
.hasAttributes(ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.toParameter()
.assertParameterAnnotation("Max")
.hasAttributes(ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
));
KotlinFileAssert.assertThat(files.get("LongTest.kt"))
.assertClass("LongTest")
.assertPrimaryConstructorParameter("field1")
.assertParameterAnnotation("Min", "get")
.hasAttributes(ImmutableMap.of(
"value", "1L",
"message", "\"Must be positive\""
))
.toPrimaryConstructorParameter()
.assertParameterAnnotation("Max", "get")
.hasAttributes(ImmutableMap.of(
"value", "99L",
"message", "\"Must be less than 100\""
))
.toPrimaryConstructorParameter()
.toClass()
.assertPrimaryConstructorParameter("field2")
.assertParameterAnnotation("Min", "get")
.hasNotAttributes(List.of("message"))
.toPrimaryConstructorParameter()
.assertParameterAnnotation("Max", "get")
.hasNotAttributes(List.of("message"));
}
private Map<String, File> generateFromContract(String url) throws IOException {
return generateFromContract(url, new HashMap<>(), new HashMap<>());
}

View File

@@ -2935,6 +2935,16 @@ components:
description: list of named parameters for current message
additionalProperties:
type: string
ListAlias:
type: array
items:
type: string
DeepListAlias:
type: array
items:
type: array
items:
type: string
TestResult:
type: object
allOf:

View File

@@ -2079,22 +2079,29 @@ components:
TestEnum:
type: string
enum:
- ""
- "1"
- "2"
- ''
- 'value_one'
- 'value_two'
title: TestEnum
TestItem:
ObjectWithEnum:
type: object
required:
- test
properties:
test:
type: integer
title: test
testEmum:
$ref: '#/components/schemas/TestEnum'
default: ""
title: TestItem
attribute:
allOf:
- $ref: '#/components/schemas/TestEnum'
default: ''
title: ObjectWithEnum
ObjectWithInlineEnumDefaultValue:
type: object
properties:
attribute:
description: 'Object one attribute enum with default value'
type: 'string'
enum: [
'value_one',
'value_two'
]
default: 'value_one'
ObjectWithInlineEnum:
type: object
properties:

View File

@@ -7,6 +7,18 @@ info:
servers:
- url: http://api.example.xyz/v1
paths:
/v1/person:
get:
operationId: list
responses:
'200':
description: OK
/v2/person:
get:
operationId: list
responses:
'200':
description: OK
/person/display/{personId}:
get:
tags:
@@ -47,6 +59,7 @@ paths:
schema:
$ref: "#/components/schemas/Person"
put:
x-role: admin
tags:
- person
parameters:
@@ -83,4 +96,4 @@ components:
type: object
properties:
test:
type: string
type: string

View File

@@ -0,0 +1,310 @@
openapi: 3.0.3
info:
title: sample spec
version: 1.0.0
paths:
/test/length/{word}:
post:
operationId: lengthTest
parameters:
- in: path
name: word
required: true
schema:
type: string
maxLength: 10
x-size-message: "Must be max 10 characters"
- in: query
name: token
required: true
schema:
type: string
minLength: 1
x-size-message: "Must not be empty"
- in: header
name: clientId
required: true
schema:
type: string
minLength: 3
maxLength: 5
x-size-message: "Must be between 3 and 5 characters"
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/LengthTest'
responses:
201:
description: success
/test/size/{values}:
post:
operationId: sizeTest
parameters:
- in: path
name: values
required: true
schema:
type: array
maxItems: 10
x-size-message: "Must be max 10 elements"
items:
type: string
- in: query
name: tokens
required: true
schema:
type: array
minItems: 1
x-size-message: "Must not be empty"
items:
type: string
- in: header
name: clientIds
required: true
schema:
type: array
minItems: 3
maxItems: 5
x-size-message: "Must be between 3 and 5 elements"
items:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SizeTest'
responses:
201:
description: success
/test/number/minmax/{number}:
post:
operationId: minmaxNumberTest
parameters:
- in: path
name: number
required: true
schema:
type: number
minimum: 0.1
maximum: 99.9
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
- in: query
name: token
required: true
schema:
type: number
minimum: 0.1
maximum: 99.9
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
- in: header
name: clientNumber
required: true
schema:
type: number
minimum: 0.1
maximum: 99.9
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/NumberTest'
responses:
201:
description: success
/test/integer/minmax/{number}:
post:
operationId: minmaxIntegerTest
parameters:
- in: path
name: number
required: true
schema:
type: integer
format: int32
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
- in: query
name: token
required: true
schema:
type: integer
format: int32
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
- in: header
name: clientNumber
required: true
schema:
type: integer
format: int32
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/IntegerTest'
responses:
201:
description: success
/test/long/minmax/{number}:
post:
operationId: minmaxLongTest
parameters:
- in: path
name: number
required: true
schema:
type: integer
format: int64
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
- in: query
name: token
required: true
schema:
type: integer
format: int64
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
- in: header
name: clientNumber
required: true
schema:
type: integer
format: int64
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/LongTest'
responses:
201:
description: success
components:
schemas:
LengthTest:
type: object
properties:
field1:
type: string
maxLength: 10
x-size-message: "Must be max 10 characters"
field2:
type: string
minLength: 1
x-size-message: "Must not be empty"
field3:
type: string
minLength: 3
maxLength: 5
x-size-message: "Must be between 3 and 5 characters"
field4:
type: string
minLength: 3
maxLength: 5
field5:
type: string
minLength: 3
field6:
type: string
maxLength: 5
SizeTest:
type: object
properties:
field1:
type: array
maxItems: 10
x-size-message: "Must be max 10 elements"
items:
type: string
field2:
type: array
minItems: 1
x-size-message: "Must not be empty"
items:
type: string
field3:
type: array
minItems: 3
maxItems: 5
x-size-message: "Must be between 3 and 5 elements"
items:
type: string
field4:
type: array
minItems: 3
maxItems: 5
items:
type: string
field5:
type: array
minItems: 3
items:
type: string
field6:
type: array
maxItems: 5
items:
type: string
NumberTest:
type: object
properties:
field1:
type: number
minimum: 0.1
maximum: 99.9
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
field2:
type: number
minimum: 0.1
maximum: 99.9
IntegerTest:
type: object
properties:
field1:
type: integer
format: int32
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
field2:
type: integer
format: int32
minimum: 1
maximum: 99
LongTest:
properties:
field1:
type: integer
format: int64
minimum: 1
maximum: 99
x-minimum-message: "Must be positive"
x-maximum-message: "Must be less than 100"
field2:
type: integer
format: int64
minimum: 1
maximum: 99

View File

@@ -0,0 +1,48 @@
---
# Corresponds to bug report 21680: https://github.com/openapitools/openapi-generator/issues/21680
openapi: 3.0.1
info:
title: API that has problem with OpenAPI Generator
version: 1.0.0
paths:
"/forbiddenaccesscsrf":
get:
summary: Forbidden access CSRF
operationId: forbiddenAccessCsrfGet
responses:
'403':
description: Expected response
content:
application/json:
schema:
"$ref": "#/components/schemas/errors"
components:
schemas:
error:
required:
- code
- horodatage
- message
type: object
properties:
code:
type: string
description: Short error description
message:
type: string
description: Complete human readable description
error_uri:
type: string
description: Detailed error description URI
format: uri
horodatage:
type: string
description: Date time of occurence
format: date-time
errors:
type: array
properties:
empty:
type: boolean
items:
"$ref": "#/components/schemas/error"

View File

@@ -0,0 +1,182 @@
openapi: 3.0.0
servers:
- url: 'https://example.org/v1'
info:
description: >-
Example created for nullable multipartfile issue
version: 1.0.0
title: OpenAPI Stuff API created to reproduce issue
license:
name: Apache-2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
tags:
- name: multipartfile
description: All about the nullable multipartfile
security:
- bearerAuth: []
paths:
/nullable-multipartfile:
post:
tags:
- multipartfile
summary: simple nullable multipartfile
operationId: testNullableMultipartfile
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
description: File to upload
format: binary
nullable: true
jsonPayload:
type: object
description: simple json payload
properties:
name:
type: string
required:
- jsonPayload
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: string
'400':
description: Invalid status value
/nullable-multipartfile-array:
post:
tags:
- multipartfile
summary: simple nullable multipartfile
operationId: testNullableMultipartfile
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
files:
type: array
items:
type: string
description: File to upload
format: binary
nullable: true
jsonPayload:
type: object
description: simple json payload
properties:
name:
type: string
required:
- jsonPayload
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: string
'400':
description: Invalid status value
/non-nullable-multipartfile:
post:
tags:
- multipartfile
summary: simple non nullable multipartfile
operationId: testNonNullableMultipartfile
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
description: File to upload
format: binary
nullable: false
jsonPayload:
type: object
description: simple json payload
properties:
name:
type: string
required:
- jsonPayload
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: string
'400':
description: Invalid status value
/non-nullable-multipartfile-array:
post:
tags:
- multipartfile
summary: simple non nullable multipartfile
operationId: testNonNullableMultipartfile
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
files:
type: array
items:
type: string
description: File to upload
format: binary
nullable: false
jsonPayload:
type: object
description: simple json payload
properties:
name:
type: string
required:
- jsonPayload
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: string
'400':
description: Invalid status value
externalDocs:
description: Find out more about Swagger
url: 'http://swagger.io'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
Stuff:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
required:
- name

View File

@@ -0,0 +1,22 @@
openapi: 3.1.0
info:
title: Security scheme test
version: 1.0.0
paths:
/test:
get:
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: string
components:
securitySchemes:
openId:
type: openIdConnect
openIdConnectUrl: https://localhost:8443
security:
- openId:
- test

View File

@@ -12,7 +12,6 @@
* Do not edit the class manually.
*/
import type { Configuration } from "./configuration";
import type { RequestArgs } from "./base";
import type { AxiosInstance, AxiosResponse } from 'axios';
@@ -63,6 +62,7 @@ export const setOAuthToObject = async function (object: any, name: string, scope
}
}
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
if (parameter == null) return;
if (typeof parameter === "object") {

View File

@@ -1,5 +1,4 @@
/* tslint:disable */
/* eslint-disable */
/**
* Echo Server API
* Echo Server API
@@ -12,12 +11,24 @@
* Do not edit the class manually.
*/
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;
@@ -44,6 +55,17 @@ 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
*/
@@ -70,6 +92,7 @@ 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

@@ -129,17 +129,20 @@ components:
allOf:
- $ref: "#/components/schemas/Addressable"
- $ref: "#/components/schemas/Extensible"
description: Entity reference schema to be use for all entityRef class.
- description: Entity reference schema to be use for all entityRef class.
properties:
name:
description: Name of the related entity.
type: string
'@referredType':
description: The actual type of the target instance when needed for disambiguation.
type: string
type: object
example: null
discriminator:
propertyName: '@type'
properties:
name:
description: Name of the related entity.
type: string
'@referredType':
description: The actual type of the target instance when needed for disambiguation.
type: string
type: object
example: null
FooRefOrValue:
discriminator:
propertyName: '@type'
@@ -151,22 +154,32 @@ components:
Foo:
allOf:
- $ref: "#/components/schemas/Entity"
- properties:
fooPropA:
type: string
fooPropB:
type: string
type: object
example: null
example:
'@baseType': '@baseType'
'@type': '@type'
fooPropA: fooPropA
href: href
id: id
fooPropB: fooPropB
properties:
fooPropA:
type: string
fooPropB:
type: string
'@schemaLocation': '@schemaLocation'
type: object
FooRef:
allOf:
- $ref: "#/components/schemas/EntityRef"
properties:
foorefPropA:
type: string
- properties:
foorefPropA:
type: string
type: object
example: null
type: object
example: null
BarRef:
allOf:
- $ref: "#/components/schemas/EntityRef"
@@ -174,35 +187,49 @@ components:
Bar_Create:
allOf:
- $ref: "#/components/schemas/Entity"
properties:
barPropA:
type: string
fooPropB:
type: string
foo:
$ref: "#/components/schemas/FooRefOrValue"
- properties:
barPropA:
type: string
fooPropB:
type: string
foo:
$ref: "#/components/schemas/FooRefOrValue"
type: object
example: null
type: object
example: null
Bar:
allOf:
- $ref: "#/components/schemas/Entity"
- properties:
id:
type: string
barPropA:
type: string
fooPropB:
type: string
foo:
$ref: "#/components/schemas/FooRefOrValue"
required:
- id
type: object
example: null
example:
'@baseType': '@baseType'
'@type': '@type'
foo:
'@baseType': '@baseType'
'@type': '@type'
fooPropA: fooPropA
href: href
id: id
fooPropB: fooPropB
'@schemaLocation': '@schemaLocation'
href: href
id: id
fooPropB: fooPropB
'@schemaLocation': '@schemaLocation'
barPropA: barPropA
properties:
id:
type: string
barPropA:
type: string
fooPropB:
type: string
foo:
$ref: "#/components/schemas/FooRefOrValue"
required:
- id
type: object
BarRefOrValue:
oneOf:
@@ -213,24 +240,33 @@ components:
Pizza:
allOf:
- $ref: "#/components/schemas/Entity"
properties:
pizzaSize:
type: number
- properties:
pizzaSize:
type: number
type: object
example: null
type: object
example: null
Pasta:
allOf:
- $ref: "#/components/schemas/Entity"
properties:
vendor:
type: string
- properties:
vendor:
type: string
type: object
example: null
type: object
example: null
PizzaSpeziale:
allOf:
- $ref: "#/components/schemas/Pizza"
properties:
toppings:
type: string
- properties:
toppings:
type: string
type: object
example: null
type: object
example: null
FruitType:
enum:
- APPLE

View File

@@ -2,19 +2,18 @@
# EntityRef
Entity reference schema to be use for all entityRef class.
## Properties
| Name | Type | Description | Notes |
|------------ | ------------- | ------------- | -------------|
|**name** | **String** | Name of the related entity. | [optional] |
|**atReferredType** | **String** | The actual type of the target instance when needed for disambiguation. | [optional] |
|**href** | **String** | Hyperlink reference | [optional] |
|**id** | **String** | unique identifier | [optional] |
|**atSchemaLocation** | **String** | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional] |
|**atBaseType** | **String** | When sub-classing, this defines the super-class | [optional] |
|**atType** | **String** | When sub-classing, this defines the sub-class Extensible name | |
|**name** | **String** | Name of the related entity. | [optional] |
|**atReferredType** | **String** | The actual type of the target instance when needed for disambiguation. | [optional] |

View File

@@ -28,16 +28,16 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonTypeName;
/**
* Entity reference schema to be use for all entityRef class.
* EntityRef
*/
@JsonPropertyOrder({
EntityRef.JSON_PROPERTY_NAME,
EntityRef.JSON_PROPERTY_AT_REFERRED_TYPE,
EntityRef.JSON_PROPERTY_HREF,
EntityRef.JSON_PROPERTY_ID,
EntityRef.JSON_PROPERTY_AT_SCHEMA_LOCATION,
EntityRef.JSON_PROPERTY_AT_BASE_TYPE,
EntityRef.JSON_PROPERTY_AT_TYPE
EntityRef.JSON_PROPERTY_AT_TYPE,
EntityRef.JSON_PROPERTY_NAME,
EntityRef.JSON_PROPERTY_AT_REFERRED_TYPE
})
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.17.0-SNAPSHOT")
@JsonIgnoreProperties(
@@ -51,14 +51,6 @@ import com.fasterxml.jackson.annotation.JsonTypeName;
})
public class EntityRef {
public static final String JSON_PROPERTY_NAME = "name";
@javax.annotation.Nullable
protected String name;
public static final String JSON_PROPERTY_AT_REFERRED_TYPE = "@referredType";
@javax.annotation.Nullable
protected String atReferredType;
public static final String JSON_PROPERTY_HREF = "href";
@javax.annotation.Nullable
protected String href;
@@ -79,59 +71,17 @@ public class EntityRef {
// The discriminator does not have Nullability-annotation since it is added during serialization by the @JsonTypeName annotation
protected String atType;
public static final String JSON_PROPERTY_NAME = "name";
@javax.annotation.Nullable
protected String name;
public static final String JSON_PROPERTY_AT_REFERRED_TYPE = "@referredType";
@javax.annotation.Nullable
protected String atReferredType;
public EntityRef() {
}
public EntityRef name(@javax.annotation.Nullable String name) {
this.name = name;
return this;
}
/**
* Name of the related entity.
* @return name
*/
@javax.annotation.Nullable
@JsonProperty(value = JSON_PROPERTY_NAME, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public String getName() {
return name;
}
@JsonProperty(value = JSON_PROPERTY_NAME, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public void setName(@javax.annotation.Nullable String name) {
this.name = name;
}
public EntityRef atReferredType(@javax.annotation.Nullable String atReferredType) {
this.atReferredType = atReferredType;
return this;
}
/**
* The actual type of the target instance when needed for disambiguation.
* @return atReferredType
*/
@javax.annotation.Nullable
@JsonProperty(value = JSON_PROPERTY_AT_REFERRED_TYPE, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public String getAtReferredType() {
return atReferredType;
}
@JsonProperty(value = JSON_PROPERTY_AT_REFERRED_TYPE, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public void setAtReferredType(@javax.annotation.Nullable String atReferredType) {
this.atReferredType = atReferredType;
}
public EntityRef href(@javax.annotation.Nullable String href) {
this.href = href;
@@ -257,6 +207,56 @@ public class EntityRef {
this.atType = atType;
}
public EntityRef name(@javax.annotation.Nullable String name) {
this.name = name;
return this;
}
/**
* Name of the related entity.
* @return name
*/
@javax.annotation.Nullable
@JsonProperty(value = JSON_PROPERTY_NAME, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public String getName() {
return name;
}
@JsonProperty(value = JSON_PROPERTY_NAME, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public void setName(@javax.annotation.Nullable String name) {
this.name = name;
}
public EntityRef atReferredType(@javax.annotation.Nullable String atReferredType) {
this.atReferredType = atReferredType;
return this;
}
/**
* The actual type of the target instance when needed for disambiguation.
* @return atReferredType
*/
@javax.annotation.Nullable
@JsonProperty(value = JSON_PROPERTY_AT_REFERRED_TYPE, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public String getAtReferredType() {
return atReferredType;
}
@JsonProperty(value = JSON_PROPERTY_AT_REFERRED_TYPE, required = false)
@JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public void setAtReferredType(@javax.annotation.Nullable String atReferredType) {
this.atReferredType = atReferredType;
}
@Override
public boolean equals(Object o) {
@@ -267,31 +267,31 @@ public class EntityRef {
return false;
}
EntityRef entityRef = (EntityRef) o;
return Objects.equals(this.name, entityRef.name) &&
Objects.equals(this.atReferredType, entityRef.atReferredType) &&
Objects.equals(this.href, entityRef.href) &&
return Objects.equals(this.href, entityRef.href) &&
Objects.equals(this.id, entityRef.id) &&
Objects.equals(this.atSchemaLocation, entityRef.atSchemaLocation) &&
Objects.equals(this.atBaseType, entityRef.atBaseType) &&
Objects.equals(this.atType, entityRef.atType);
Objects.equals(this.atType, entityRef.atType) &&
Objects.equals(this.name, entityRef.name) &&
Objects.equals(this.atReferredType, entityRef.atReferredType);
}
@Override
public int hashCode() {
return Objects.hash(name, atReferredType, href, id, atSchemaLocation, atBaseType, atType);
return Objects.hash(href, id, atSchemaLocation, atBaseType, atType, name, atReferredType);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class EntityRef {\n");
sb.append(" name: ").append(toIndentedString(name)).append("\n");
sb.append(" atReferredType: ").append(toIndentedString(atReferredType)).append("\n");
sb.append(" href: ").append(toIndentedString(href)).append("\n");
sb.append(" id: ").append(toIndentedString(id)).append("\n");
sb.append(" atSchemaLocation: ").append(toIndentedString(atSchemaLocation)).append("\n");
sb.append(" atBaseType: ").append(toIndentedString(atBaseType)).append("\n");
sb.append(" atType: ").append(toIndentedString(atType)).append("\n");
sb.append(" name: ").append(toIndentedString(name)).append("\n");
sb.append(" atReferredType: ").append(toIndentedString(atReferredType)).append("\n");
sb.append("}");
return sb.toString();
}

View File

@@ -4,14 +4,14 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**id** | **String** | |
**bar_prop_a** | Option<**String**> | | [optional]
**foo_prop_b** | Option<**String**> | | [optional]
**foo** | Option<[**models::FooRefOrValue**](FooRefOrValue.md)> | | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | **String** | |
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**bar_prop_a** | Option<**String**> | | [optional]
**foo_prop_b** | Option<**String**> | | [optional]
**foo** | Option<[**models::FooRefOrValue**](FooRefOrValue.md)> | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -4,14 +4,14 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**bar_prop_a** | Option<**String**> | | [optional]
**foo_prop_b** | Option<**String**> | | [optional]
**foo** | Option<[**models::FooRefOrValue**](FooRefOrValue.md)> | | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | Option<**String**> | unique identifier | [optional]
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**bar_prop_a** | Option<**String**> | | [optional]
**foo_prop_b** | Option<**String**> | | [optional]
**foo** | Option<[**models::FooRefOrValue**](FooRefOrValue.md)> | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -4,13 +4,13 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**name** | Option<**String**> | Name of the related entity. | [optional]
**at_referred_type** | Option<**String**> | The actual type of the target instance when needed for disambiguation. | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | Option<**String**> | unique identifier | [optional]
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**name** | Option<**String**> | Name of the related entity. | [optional]
**at_referred_type** | Option<**String**> | The actual type of the target instance when needed for disambiguation. | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -4,13 +4,13 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**foo_prop_a** | Option<**String**> | | [optional]
**foo_prop_b** | Option<**String**> | | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | Option<**String**> | unique identifier | [optional]
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**foo_prop_a** | Option<**String**> | | [optional]
**foo_prop_b** | Option<**String**> | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -4,14 +4,14 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**fooref_prop_a** | Option<**String**> | | [optional]
**name** | Option<**String**> | Name of the related entity. | [optional]
**at_referred_type** | Option<**String**> | The actual type of the target instance when needed for disambiguation. | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | Option<**String**> | unique identifier | [optional]
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**name** | Option<**String**> | Name of the related entity. | [optional]
**at_referred_type** | Option<**String**> | The actual type of the target instance when needed for disambiguation. | [optional]
**fooref_prop_a** | Option<**String**> | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -4,12 +4,12 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**vendor** | Option<**String**> | | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | Option<**String**> | unique identifier | [optional]
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**vendor** | Option<**String**> | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -4,12 +4,12 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**pizza_size** | Option<**f64**> | | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | Option<**String**> | unique identifier | [optional]
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**pizza_size** | Option<**f64**> | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -4,13 +4,13 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**toppings** | Option<**String**> | | [optional]
**pizza_size** | Option<**f64**> | | [optional]
**href** | Option<**String**> | Hyperlink reference | [optional]
**id** | Option<**String**> | unique identifier | [optional]
**at_schema_location** | Option<**String**> | A URI to a JSON-Schema file that defines additional attributes and relationships | [optional]
**at_base_type** | Option<**String**> | When sub-classing, this defines the super-class | [optional]
**at_type** | **String** | When sub-classing, this defines the sub-class Extensible name |
**pizza_size** | Option<**f64**> | | [optional]
**toppings** | Option<**String**> | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -13,17 +13,11 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct Bar {
#[serde(rename = "id")]
pub id: String,
#[serde(rename = "barPropA", skip_serializing_if = "Option::is_none")]
pub bar_prop_a: Option<String>,
#[serde(rename = "fooPropB", skip_serializing_if = "Option::is_none")]
pub foo_prop_b: Option<String>,
#[serde(rename = "foo", skip_serializing_if = "Option::is_none")]
pub foo: Option<Box<models::FooRefOrValue>>,
/// Hyperlink reference
#[serde(rename = "href", skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
#[serde(rename = "id")]
pub id: String,
/// A URI to a JSON-Schema file that defines additional attributes and relationships
#[serde(rename = "@schemaLocation", skip_serializing_if = "Option::is_none")]
pub at_schema_location: Option<String>,
@@ -33,19 +27,25 @@ pub struct Bar {
/// When sub-classing, this defines the sub-class Extensible name
#[serde(rename = "@type")]
pub at_type: String,
#[serde(rename = "barPropA", skip_serializing_if = "Option::is_none")]
pub bar_prop_a: Option<String>,
#[serde(rename = "fooPropB", skip_serializing_if = "Option::is_none")]
pub foo_prop_b: Option<String>,
#[serde(rename = "foo", skip_serializing_if = "Option::is_none")]
pub foo: Option<Box<models::FooRefOrValue>>,
}
impl Bar {
pub fn new(id: String, at_type: String) -> Bar {
Bar {
id,
bar_prop_a: None,
foo_prop_b: None,
foo: None,
href: None,
id,
at_schema_location: None,
at_base_type: None,
at_type,
bar_prop_a: None,
foo_prop_b: None,
foo: None,
}
}
}

View File

@@ -13,12 +13,6 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct BarCreate {
#[serde(rename = "barPropA", skip_serializing_if = "Option::is_none")]
pub bar_prop_a: Option<String>,
#[serde(rename = "fooPropB", skip_serializing_if = "Option::is_none")]
pub foo_prop_b: Option<String>,
#[serde(rename = "foo", skip_serializing_if = "Option::is_none")]
pub foo: Option<Box<models::FooRefOrValue>>,
/// Hyperlink reference
#[serde(rename = "href", skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
@@ -34,19 +28,25 @@ pub struct BarCreate {
/// When sub-classing, this defines the sub-class Extensible name
#[serde(rename = "@type")]
pub at_type: String,
#[serde(rename = "barPropA", skip_serializing_if = "Option::is_none")]
pub bar_prop_a: Option<String>,
#[serde(rename = "fooPropB", skip_serializing_if = "Option::is_none")]
pub foo_prop_b: Option<String>,
#[serde(rename = "foo", skip_serializing_if = "Option::is_none")]
pub foo: Option<Box<models::FooRefOrValue>>,
}
impl BarCreate {
pub fn new(at_type: String) -> BarCreate {
BarCreate {
bar_prop_a: None,
foo_prop_b: None,
foo: None,
href: None,
id: None,
at_schema_location: None,
at_base_type: None,
at_type,
bar_prop_a: None,
foo_prop_b: None,
foo: None,
}
}
}

View File

@@ -13,12 +13,6 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct BarRef {
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
pub at_referred_type: Option<String>,
/// Hyperlink reference
#[serde(rename = "href", skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
@@ -34,18 +28,24 @@ pub struct BarRef {
/// When sub-classing, this defines the sub-class Extensible name
#[serde(rename = "@type")]
pub at_type: String,
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
pub at_referred_type: Option<String>,
}
impl BarRef {
pub fn new(at_type: String) -> BarRef {
BarRef {
name: None,
at_referred_type: None,
href: None,
id: None,
at_schema_location: None,
at_base_type: None,
at_type,
name: None,
at_referred_type: None,
}
}
}

View File

@@ -11,18 +11,11 @@
use crate::models;
use serde::{Deserialize, Serialize};
/// EntityRef : Entity reference schema to be use for all entityRef class.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "@type")]
pub enum EntityRef {
#[serde(rename="BarRef")]
BarRef {
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
at_referred_type: Option<String>,
/// Hyperlink reference
#[serde(rename = "href", skip_serializing_if = "Option::is_none")]
href: Option<String>,
@@ -35,15 +28,15 @@ pub enum EntityRef {
/// When sub-classing, this defines the super-class
#[serde(rename = "@baseType", skip_serializing_if = "Option::is_none")]
at_base_type: Option<String>,
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
at_referred_type: Option<String>,
},
#[serde(rename="FooRef")]
FooRef {
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
at_referred_type: Option<String>,
/// Hyperlink reference
#[serde(rename = "href", skip_serializing_if = "Option::is_none")]
href: Option<String>,
@@ -56,18 +49,24 @@ pub enum EntityRef {
/// When sub-classing, this defines the super-class
#[serde(rename = "@baseType", skip_serializing_if = "Option::is_none")]
at_base_type: Option<String>,
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
at_referred_type: Option<String>,
},
}
impl Default for EntityRef {
fn default() -> Self {
Self::BarRef {
name: Default::default(),
at_referred_type: Default::default(),
href: Default::default(),
id: Default::default(),
at_schema_location: Default::default(),
at_base_type: Default::default(),
name: Default::default(),
at_referred_type: Default::default(),
}
}

View File

@@ -13,10 +13,6 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct Foo {
#[serde(rename = "fooPropA", skip_serializing_if = "Option::is_none")]
pub foo_prop_a: Option<String>,
#[serde(rename = "fooPropB", skip_serializing_if = "Option::is_none")]
pub foo_prop_b: Option<String>,
/// Hyperlink reference
#[serde(rename = "href", skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
@@ -32,18 +28,22 @@ pub struct Foo {
/// When sub-classing, this defines the sub-class Extensible name
#[serde(rename = "@type")]
pub at_type: String,
#[serde(rename = "fooPropA", skip_serializing_if = "Option::is_none")]
pub foo_prop_a: Option<String>,
#[serde(rename = "fooPropB", skip_serializing_if = "Option::is_none")]
pub foo_prop_b: Option<String>,
}
impl Foo {
pub fn new(at_type: String) -> Foo {
Foo {
foo_prop_a: None,
foo_prop_b: None,
href: None,
id: None,
at_schema_location: None,
at_base_type: None,
at_type,
foo_prop_a: None,
foo_prop_b: None,
}
}
}

View File

@@ -13,14 +13,6 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct FooRef {
#[serde(rename = "foorefPropA", skip_serializing_if = "Option::is_none")]
pub fooref_prop_a: Option<String>,
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
pub at_referred_type: Option<String>,
/// Hyperlink reference
#[serde(rename = "href", skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
@@ -36,19 +28,27 @@ pub struct FooRef {
/// When sub-classing, this defines the sub-class Extensible name
#[serde(rename = "@type")]
pub at_type: String,
/// Name of the related entity.
#[serde(rename = "name", skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// The actual type of the target instance when needed for disambiguation.
#[serde(rename = "@referredType", skip_serializing_if = "Option::is_none")]
pub at_referred_type: Option<String>,
#[serde(rename = "foorefPropA", skip_serializing_if = "Option::is_none")]
pub fooref_prop_a: Option<String>,
}
impl FooRef {
pub fn new(at_type: String) -> FooRef {
FooRef {
fooref_prop_a: None,
name: None,
at_referred_type: None,
href: None,
id: None,
at_schema_location: None,
at_base_type: None,
at_type,
name: None,
at_referred_type: None,
fooref_prop_a: None,
}
}
}

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