diff --git a/.github/workflows/samples-spring.yaml b/.github/workflows/samples-spring.yaml index 7f0a903ace3d..b8d0397e13fc 100644 --- a/.github/workflows/samples-spring.yaml +++ b/.github/workflows/samples-spring.yaml @@ -44,6 +44,8 @@ jobs: - samples/server/petstore/spring-boot-nullable-set - samples/server/petstore/spring-boot-defaultInterface-unhandledExcp - samples/server/petstore/springboot + - samples/server/petstore/springboot-byte-format-edge-cases + - samples/server/petstore/springboot-byte-format-edge-cases-reactive - samples/server/petstore/springboot-beanvalidation - samples/server/petstore/springboot-builtin-validation - samples/server/petstore/springboot-delegate diff --git a/bin/configs/spring-boot-byte-format-edge-cases-reactive.yaml b/bin/configs/spring-boot-byte-format-edge-cases-reactive.yaml new file mode 100644 index 000000000000..b4a874f984a3 --- /dev/null +++ b/bin/configs/spring-boot-byte-format-edge-cases-reactive.yaml @@ -0,0 +1,11 @@ +generatorName: spring +outputDir: samples/server/petstore/springboot-byte-format-edge-cases-reactive +inputSpec: modules/openapi-generator/src/test/resources/3_0/spring/byte-format-edge-cases.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaSpring +additionalProperties: + artifactId: springboot + snapshotVersion: "true" + hideGenerationTimestamp: "true" + reactive: true + interfaceOnly: "true" + requestMappingMode: "none" diff --git a/bin/configs/spring-boot-byte-format-edge-cases.yaml b/bin/configs/spring-boot-byte-format-edge-cases.yaml new file mode 100644 index 000000000000..4dec629decf8 --- /dev/null +++ b/bin/configs/spring-boot-byte-format-edge-cases.yaml @@ -0,0 +1,10 @@ +generatorName: spring +outputDir: samples/server/petstore/springboot-byte-format-edge-cases +inputSpec: modules/openapi-generator/src/test/resources/3_0/spring/byte-format-edge-cases.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaSpring +additionalProperties: + artifactId: springboot + snapshotVersion: "true" + hideGenerationTimestamp: "true" + interfaceOnly: "true" + requestMappingMode: "none" diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 2c3c584e931a..4b4073da1c32 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -647,6 +647,27 @@ public void processOpts() { additionalProperties.put("lambdaSplitString", new SplitStringLambda()); + // Lambda to add type comment only if actual type differs from implemented type + // Format: "implementedType|actualType" -> " /* actualType */" or "" + additionalProperties.put("lambdaTypeComment", (Mustache.Lambda) (fragment, writer) -> { + String input = fragment.execute().trim(); + String[] parts = input.split("\\|", 2); + if (parts.length == 2) { + String implementedType = parts[0].trim(); + String actualType = parts[1].trim(); + + // Only add comment if types differ + if (!implementedType.equals(actualType)) { + // Also check if implementedType is a collection of actualType (e.g., List vs String) + String expectedCollection = "List<" + actualType + ">"; + String expectedFlux = "Flux<" + actualType + ">"; + if (!implementedType.equals(expectedCollection) && !implementedType.equals(expectedFlux)) { + writer.write(" /* " + actualType + " */"); + } + } + } + }); + // apiController: hide implementation behind undocumented flag to temporarily preserve code additionalProperties.put("_api_controller_impl_", false); // HEADS-UP: Do not add more template file after this block @@ -798,6 +819,8 @@ public void setIsVoid(boolean isVoid) { prepareVersioningParameters(ops); handleImplicitHeaders(operation); + convertByteArrayParamsToStringType(operation); + markMultipartFormDataParameters(operation); } // The tag for the controller is the first tag of the first operation final CodegenOperation firstOperation = ops.get(0); @@ -813,6 +836,64 @@ public void setIsVoid(boolean isVoid) { return objs; } + /** + * Converts parameters of type {@code byte[]} (i.e., OpenAPI {@code type: string, format: byte}) to {@code String}. + *

+ * In OpenAPI, {@code type: string, format: byte} is a base64-encoded string. However, Spring does not automatically + * decode base64-encoded request parameters into {@code byte[]} for query, path, header, cookie, or form parameters. + * Therefore, these parameters are mapped to {@code String} to avoid incorrect type handling and to ensure the + * application receives the raw base64 string as provided by the client. + *

+ * + * @param operation the codegen operation whose parameters will be checked and converted if necessary + **/ + private void convertByteArrayParamsToStringType(CodegenOperation operation) { + var convertedParams = operation.allParams.stream() + .filter(CodegenParameter::getIsByteArray) + .filter(param -> param.isQueryParam || param.isPathParam || param.isHeaderParam || param.isCookieParam || param.isFormParam) + .peek(param -> param.dataType = "String") + .collect(Collectors.toList()); + LOGGER.info("Converted parameters [{}] from byte[] to String in operation [{}]", convertedParams.stream().map(param -> param.paramName).collect(Collectors.toList()), operation.operationId); + } + + /** + * Marks form parameters that are in multipart/form-data operations for special handling in reactive mode. + *

+ * In reactive Spring WebFlux, multipart/form-data parameters must use @RequestPart instead of @RequestParam, + * and non-model parameters (primitives, enums, strings) must be received as String or Flux<String> and + * converted manually in the implementation. + *

+ * + * @param operation the codegen operation whose parameters will be marked if necessary + **/ + private void markMultipartFormDataParameters(CodegenOperation operation) { + if (!reactive) { + return; // Only applies to reactive mode + } + + // Check if this operation consumes multipart/form-data + boolean isMultipartFormData = false; + if (operation.hasConsumes) { + for (Map consume : operation.consumes) { + if ("multipart/form-data".equals(consume.get("mediaType"))) { + isMultipartFormData = true; + break; + } + } + } + + if (!isMultipartFormData) { + return; + } + + // Mark all form parameters as multipart form data + for (CodegenParameter param : operation.allParams) { + if (param.isFormParam) { + param.vendorExtensions.put("x-isMultipartFormData", true); + } + } + } + private interface DataTypeAssigner { void setReturnType(String returnType); diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/cookieParams.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/cookieParams.mustache index a255b5c7daf2..ef9ffa8efada 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/cookieParams.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/cookieParams.mustache @@ -1 +1 @@ -{{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @CookieValue(name = "{{baseName}}"{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{/isCookieParam}} \ No newline at end of file +{{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @CookieValue(name = "{{baseName}}"{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{#isByteArray}} /* base64 encoded binary */{{/isByteArray}}{{/isCookieParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache index eaa958fc42c6..043f19a46fb8 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache @@ -1 +1 @@ -{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#useBeanValidation}} {{>beanValidationBodyParams}}@Valid{{/useBeanValidation}} {{#isModel}}@RequestPart{{/isModel}}{{^isModel}}{{#isArray}}@RequestPart{{/isArray}}{{^isArray}}{{#reactive}}@RequestPart{{/reactive}}{{^reactive}}@RequestParam{{/reactive}}{{/isArray}}{{/isModel}}(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{^required}}{{#useOptional}}Optional<{{/useOptional}}{{/required}}{{{dataType}}}{{^required}}{{#useOptional}}>{{/useOptional}}{{/required}} {{paramName}}{{/isFile}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#reactive}}{{#isArray}}Flux<{{/isArray}}Part{{#isArray}}>{{/isArray}}{{/reactive}}{{^reactive}}{{#isArray}}List<{{/isArray}}MultipartFile{{#isArray}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isFile}}{{/isFormParam}} \ No newline at end of file +{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#useBeanValidation}} {{>beanValidationBodyParams}}@Valid{{/useBeanValidation}} {{#isModel}}@RequestPart{{/isModel}}{{^isModel}}{{#isArray}}{{#items.isModel}}@RequestPart{{/items.isModel}}{{^items.isModel}}{{#reactive}}{{#vendorExtensions.x-isMultipartFormData}}@RequestPart{{/vendorExtensions.x-isMultipartFormData}}{{^vendorExtensions.x-isMultipartFormData}}@RequestParam{{/vendorExtensions.x-isMultipartFormData}}{{/reactive}}{{^reactive}}@RequestParam{{/reactive}}{{/items.isModel}}{{/isArray}}{{^isArray}}{{#reactive}}{{#vendorExtensions.x-isMultipartFormData}}@RequestPart{{/vendorExtensions.x-isMultipartFormData}}{{^vendorExtensions.x-isMultipartFormData}}@RequestParam{{/vendorExtensions.x-isMultipartFormData}}{{/reactive}}{{^reactive}}@RequestParam{{/reactive}}{{/isArray}}{{/isModel}}(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{^required}}{{#useOptional}}Optional<{{/useOptional}}{{/required}}{{#reactive}}{{#vendorExtensions.x-isMultipartFormData}}{{#isModel}}{{{dataType}}}{{/isModel}}{{^isModel}}{{#isArray}}{{#items.isModel}}{{{dataType}}}{{/items.isModel}}{{^items.isModel}}Flux{{#lambdaTypeComment}}Flux|{{{dataType}}}{{/lambdaTypeComment}}{{/items.isModel}}{{/isArray}}{{^isArray}}String{{#lambdaTypeComment}}String|{{{dataType}}}{{/lambdaTypeComment}}{{/isArray}}{{/isModel}}{{/vendorExtensions.x-isMultipartFormData}}{{^vendorExtensions.x-isMultipartFormData}}{{{dataType}}}{{/vendorExtensions.x-isMultipartFormData}}{{/reactive}}{{^reactive}}{{{dataType}}}{{/reactive}}{{^required}}{{#useOptional}}>{{/useOptional}}{{/required}} {{paramName}}{{/isFile}}{{#isByteArray}} /* base64 encoded binary */{{/isByteArray}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#reactive}}{{#isArray}}Flux<{{/isArray}}Part{{#isArray}}>{{/isArray}}{{/reactive}}{{^reactive}}{{#isArray}}List<{{/isArray}}MultipartFile{{#isArray}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isFile}}{{/isFormParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/headerParams.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/headerParams.mustache index 80b1d0a82341..7de918c2203f 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/headerParams.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/headerParams.mustache @@ -1 +1 @@ -{{#isHeaderParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @RequestHeader(value = "{{baseName}}", required = {{#required}}true{{/required}}{{^required}}false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{/isHeaderParam}} \ No newline at end of file +{{#isHeaderParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}} @RequestHeader(value = "{{baseName}}", required = {{#required}}true{{/required}}{{^required}}false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{>dateTimeParam}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{#isByteArray}} /* base64 encoded binary */{{/isByteArray}}{{/isHeaderParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/pathParams.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/pathParams.mustache index 24ebb856a153..184ff7793f2f 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/pathParams.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/pathParams.mustache @@ -1 +1 @@ -{{#isPathParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{>paramDoc}} @PathVariable("{{baseName}}"){{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>optionalDataType}} {{paramName}}{{/isPathParam}} \ No newline at end of file +{{#isPathParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{>paramDoc}} @PathVariable("{{baseName}}"){{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>optionalDataType}} {{paramName}}{{#isByteArray}} /* base64 encoded binary */{{/isByteArray}}{{/isPathParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/queryParams.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/queryParams.mustache index 56f7527eb92a..06ce33ffc58a 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/queryParams.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/queryParams.mustache @@ -1 +1 @@ -{{#isQueryParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}}{{^isModel}} @RequestParam(value = {{#isMap}}""{{/isMap}}{{^isMap}}"{{baseName}}"{{/isMap}}{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/isModel}}{{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{/isQueryParam}} \ No newline at end of file +{{#isQueryParam}}{{#vendorExtensions.x-field-extra-annotation}}{{{.}}} {{/vendorExtensions.x-field-extra-annotation}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}}{{^isModel}} @RequestParam(value = {{#isMap}}""{{/isMap}}{{^isMap}}"{{baseName}}"{{/isMap}}{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue = "{{{.}}}"{{/defaultValue}}){{/isModel}}{{>dateTimeParam}}{{#isDeprecated}} @Deprecated{{/isDeprecated}} {{>nullableAnnotation}}{{>optionalDataType}} {{paramName}}{{#isByteArray}} /* base64 encoded binary */{{/isByteArray}}{{/isQueryParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java index 94a0a6f4535e..53027796e41e 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java @@ -2690,7 +2690,7 @@ public void testRestClientFormMultipart() { + " files.stream().map(FileSystemResource::new).collect(Collectors.toList()));", // mixed - "multipartMixed(@jakarta.annotation.Nonnull MultipartMixedStatus status, @jakarta.annotation.Nonnull File _file, @jakarta.annotation.Nullable MultipartMixedRequestMarker marker, @jakarta.annotation.Nullable List statusArray)", + "multipartMixed(@jakarta.annotation.Nonnull MultipartMixedStatus status, @jakarta.annotation.Nonnull File _file, @jakarta.annotation.Nullable MultipartMixedRequestMarker marker, @jakarta.annotation.Nullable List markerArray, @jakarta.annotation.Nullable List statusArray)", "formParams.add(\"file\", new FileSystemResource(_file));", // single file @@ -2720,7 +2720,7 @@ public void testRestClientWithUseAbstractionForFiles() { "formParams.addAll(\"files\", files.stream().collect(Collectors.toList()));", // mixed - "multipartMixed(@jakarta.annotation.Nonnull MultipartMixedStatus status, org.springframework.core.io.AbstractResource _file, @jakarta.annotation.Nullable MultipartMixedRequestMarker marker, @jakarta.annotation.Nullable List statusArray)", + "multipartMixed(@jakarta.annotation.Nonnull MultipartMixedStatus status, org.springframework.core.io.AbstractResource _file, @jakarta.annotation.Nullable MultipartMixedRequestMarker marker, @jakarta.annotation.Nullable List markerArray, @jakarta.annotation.Nullable List statusArray)", "formParams.add(\"file\", _file);", // single file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/assertions/PropertyAssert.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/assertions/PropertyAssert.java index e598c210a1f6..401d87fddfca 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/assertions/PropertyAssert.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/assertions/PropertyAssert.java @@ -26,6 +26,20 @@ public PropertyAssert withType(final String expectedType) { return this; } + public PropertyAssert isArray() { + Assertions.assertThat(actual.getCommonType().isArrayType()) + .withFailMessage("Expected property %s to be array, but it was NOT", actual.getVariable(0).getNameAsString()) + .isEqualTo(true); + return this; + } + + public PropertyAssert isNotArray() { + Assertions.assertThat(actual.getCommonType().isArrayType()) + .withFailMessage("Expected property %s NOT to be array, but it was", actual.getVariable(0).getNameAsString()) + .isEqualTo(false); + return this; + } + public PropertyAnnotationsAssert assertPropertyAnnotations() { return new PropertyAnnotationsAssert(this, actual.getAnnotations()); } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index ac819033d71e..a5768399b825 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -714,7 +714,7 @@ public void testMultipartBoot() throws IOException { // Check that api validates mixed multipart request JavaFileAssert.assertThat(files.get("MultipartMixedApi.java")) - .assertMethod("multipartMixed", "MultipartMixedStatus", "MultipartFile", "MultipartMixedRequestMarker", "List") + .assertMethod("multipartMixed", "MultipartMixedStatus", "MultipartFile", "MultipartMixedRequestMarker", "List", "List") .assertParameter("status").hasType("MultipartMixedStatus") .assertParameterAnnotations() .containsWithName("Valid") @@ -728,10 +728,15 @@ public void testMultipartBoot() throws IOException { .assertParameter("marker").hasType("MultipartMixedRequestMarker") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"marker\"", "required", "false")) + // markerArray (array of objects — IMPORTANT) + .toParameter().toMethod() + .assertParameter("markerArray").hasType("List") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"markerArray\"", "required", "false")) .toParameter().toMethod() .assertParameter("statusArray").hasType("List") .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"statusArray\"", "required", "false")); + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"statusArray\"", "required", "false")); } @Test @@ -774,8 +779,8 @@ public void testReactiveMultipartBoot() throws IOException { // Check that api validates mixed multipart request JavaFileAssert.assertThat(files.get("MultipartMixedApi.java")) - .assertMethod("multipartMixed", "MultipartMixedStatus", "Part", "MultipartMixedRequestMarker", "List", "ServerWebExchange") - .assertParameter("status").hasType("MultipartMixedStatus") + .assertMethod("multipartMixed", "String", "Part", "MultipartMixedRequestMarker", "List", "Flux", "ServerWebExchange") + .assertParameter("status").hasType("String") .assertParameterAnnotations() .containsWithName("Valid") .containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"\"")) @@ -789,7 +794,12 @@ public void testReactiveMultipartBoot() throws IOException { .assertParameterAnnotations() .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"marker\"", "required", "false")) .toParameter().toMethod() - .assertParameter("statusArray").hasType("List") + // markerArray (array of objects — IMPORTANT) + .assertParameter("markerArray").hasType("List") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"markerArray\"", "required", "false")) + .toParameter().toMethod() + .assertParameter("statusArray").hasType("Flux") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"statusArray\"", "required", "false")); } @@ -864,6 +874,103 @@ public void testSchemaImplements() throws IOException { .implementsInterfaces(fooInterface, fooAnotherInterface); } + + @Test + public void shouldHandleFormatByteCorrectlyForAllApiParametersAndProperties() throws IOException { + final SpringCodegen codegen = new SpringCodegen(); + + final Map files = generateFiles(codegen, "src/test/resources/3_0/spring/byte-format-baseline.yaml"); + // Query parameters: both plain text and Base64-encoded fields are mapped to String + JavaFileAssert.assertThat(files.get("QueryApi.java")) + .assertMethod("queryParams") + .assertParameter("plain") + .hasType("String"); // plain query param → always String + JavaFileAssert.assertThat(files.get("QueryApi.java")) + .assertMethod("queryParams") + .assertParameter("bytes") + .hasType("String"); // Base64 query param → String (manual decoding needed) + + // Path parameters: same behavior as query params + JavaFileAssert.assertThat(files.get("PathApi.java")) + .assertMethod("pathParams") + .assertParameter("plain") + .hasType("String"); // path param → String + JavaFileAssert.assertThat(files.get("PathApi.java")) + .assertMethod("pathParams") + .assertParameter("bytes") + .hasType("String"); // Base64 path param → String + + // Header parameters: always String + JavaFileAssert.assertThat(files.get("HeaderApi.java")) + .assertMethod("headerParams") + .assertParameter("xPlain") + .hasType("String"); // header → String + JavaFileAssert.assertThat(files.get("HeaderApi.java")) + .assertMethod("headerParams") + .assertParameter("xByte") + .hasType("String"); // Base64 header → String + + // Cookie parameters: always String + JavaFileAssert.assertThat(files.get("CookieApi.java")) + .assertMethod("cookieParams") + .assertParameter("plain") + .hasType("String"); // cookie → String + JavaFileAssert.assertThat(files.get("CookieApi.java")) + .assertMethod("cookieParams") + .assertParameter("bytes") + .hasType("String"); // Base64 cookie → String + + // Form fields: text fields → String + JavaFileAssert.assertThat(files.get("FormApi.java")) + .assertMethod("formParams") + .assertParameter("plain") + .hasType("String"); // form field → String + JavaFileAssert.assertThat(files.get("FormApi.java")) + .assertMethod("formParams") + .assertParameter("bytes") + .hasType("String"); // Base64 form field → String + + // Multipart fields: text fields → String, files → MultipartFile + // Verifies that a simple multipart text field is generated as a String parameter + JavaFileAssert.assertThat(files.get("MultipartApi.java")) + .assertMethod("multipartParams") + .assertParameter("plain") + .hasType("String"); // multipart text field → String + + // Verifies that a Base64-encoded multipart field is treated as text (String) + // and is bound using @RequestParam rather than @RequestPart + JavaFileAssert.assertThat(files.get("MultipartApi.java")) + .assertMethod("multipartParams") + .assertParameter("bytes") + .hasType("String") // Base64 multipart text → String + .assertParameterAnnotations() + .containsWithName("RequestParam"); + + // Verifies that a binary file upload is exposed as MultipartFile + // and correctly bound from a multipart section using @RequestPart + JavaFileAssert.assertThat(files.get("MultipartApi.java")) + .assertMethod("multipartParams") + .assertParameter("file") + .hasType("MultipartFile") // binary file upload → MultipartFile + .assertParameterAnnotations() + .containsWithName("RequestPart"); + + // Form request DTO: JSON or form object mapping + JavaFileAssert.assertThat(files.get("FormParamsRequest.java")) + .assertProperty("plain") + .withType("String"); // text property → String + JavaFileAssert.assertThat(files.get("FormParamsRequest.java")) + .assertProperty("bytes") + .isArray() + .withType("byte"); // Base64 property in DTO → auto-decoded to byte[] + + // Binary request body: bound as Resource for streaming + JavaFileAssert.assertThat(files.get("BinaryBodyApi.java")) + .assertMethod("binaryBody") + .assertParameter("body") + .hasType("org.springframework.core.io.Resource"); // raw binary body → Resource (streamable) + } + @Test public void shouldAddParameterWithInHeaderWhenImplicitHeadersIsTrue_issue14418() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); @@ -4793,7 +4900,7 @@ public void testSSEOperationSupport() throws Exception { } @Test - public void givenMultipartForm_whenGenerateReactiveServer_thenParameterAreCreatedAsRequestPart() throws IOException { + public void givenMultipartForm_whenGenerateReactiveServer_thenParameterAreCreatedAsRequestParam() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); output.deleteOnExit(); String outputPath = output.getAbsolutePath().replace('\\', '/'); @@ -4816,7 +4923,6 @@ public void givenMultipartForm_whenGenerateReactiveServer_thenParameterAreCreate generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); generator.opts(input).generate(); - assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/PetApi.java"), "@Valid @RequestPart(value = \"additionalMetadata\", required = false) String additionalMetadata"); } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java index 12d52f58de59..387732414ecb 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java @@ -914,7 +914,7 @@ public void givenOctetStreamResponseType_whenGenerateServer_thenReturnTypeIsReso } @Test - public void givenMultipartForm_whenGenerateReactiveServer_thenParameterAreCreatedAsRequestPart() throws IOException { + public void givenMultipartForm_whenGenerateReactiveServer_thenParameterAreCreatedAsRequestParam() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); output.deleteOnExit(); String outputPath = output.getAbsolutePath().replace('\\', '/'); diff --git a/modules/openapi-generator/src/test/resources/3_0/form-multipart-binary-array.yaml b/modules/openapi-generator/src/test/resources/3_0/form-multipart-binary-array.yaml index 96432202560e..ec9d52977eb6 100644 --- a/modules/openapi-generator/src/test/resources/3_0/form-multipart-binary-array.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/form-multipart-binary-array.yaml @@ -66,6 +66,11 @@ paths: properties: name: type: string + markerArray: + description: "array of objects" + type: array + items: + $ref: '#/components/schemas/MultipartMixedRequestMarker' file: description: "a file" type: string @@ -87,3 +92,22 @@ components: - IN_PROGRESS - REJECTED example: REJECTED + MultipartMixedRequestMarker: + type: object + description: Marker metadata sent as JSON part in multipart request + required: + - name + properties: + name: + type: string + description: Marker name + example: example-marker + priority: + type: integer + format: int32 + description: Optional priority + example: 10 + active: + type: boolean + description: Whether the marker is active + example: true \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/byte-format-baseline.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/byte-format-baseline.yaml new file mode 100644 index 000000000000..03787495f731 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/byte-format-baseline.yaml @@ -0,0 +1,157 @@ +openapi: 3.0.3 +info: + title: Byte Format Edge Cases + version: 1.0.0 + +paths: + /query: + get: + operationId: queryParams + summary: Query parameters + parameters: + - name: plain + in: query + schema: + type: string + - name: bytes + in: query + schema: + type: string + format: byte + responses: + '204': + description: No content + + /path/{plain}/{bytes}: + get: + operationId: pathParams + summary: Path parameters + parameters: + - name: plain + in: path + required: true + schema: + type: string + - name: bytes + in: path + required: true + schema: + type: string + format: byte + responses: + '204': + description: No content + + /header: + get: + operationId: headerParams + summary: Header parameters + parameters: + - name: X-Plain + in: header + schema: + type: string + - name: X-Byte + in: header + schema: + type: string + format: byte + responses: + '204': + description: No content + + /cookie: + get: + operationId: cookieParams + summary: Cookie parameters + parameters: + - name: plain + in: cookie + schema: + type: string + - name: bytes + in: cookie + schema: + type: string + format: byte + responses: + '204': + description: No content + + /form: + post: + operationId: formParams + summary: application/x-www-form-urlencoded + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + plain: + type: string + bytes: + type: string + format: byte + responses: + '204': + description: No content + + /multipart: + post: + operationId: multipartParams + summary: multipart/form-data + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + plain: + type: string + bytes: + type: string + format: byte + file: + type: string + format: binary + responses: + '204': + description: No content + + /json-body: + post: + operationId: jsonBody + summary: JSON request body + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + plain: + type: string + bytes: + type: string + format: byte + responses: + '204': + description: No content + + /binary-body: + post: + operationId: binaryBody + summary: Raw binary body + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + '204': + description: No content diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/byte-format-edge-cases.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/byte-format-edge-cases.yaml new file mode 100644 index 000000000000..ef9a298b1601 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/byte-format-edge-cases.yaml @@ -0,0 +1,321 @@ +openapi: 3.0.3 +info: + title: Multipart & Byte Edge Case Coverage + version: 1.0.0 +servers: + - url: / +tags: + - name: coverage +paths: + /coverage/query: + get: + operationId: queryParams + parameters: + - explode: true + in: query + name: plain + required: false + schema: + type: string + style: form + - explode: true + in: query + name: bytes + required: false + schema: + format: byte + type: string + style: form + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/path/{plain}/{bytes}: + get: + operationId: pathParams + parameters: + - explode: false + in: path + name: plain + required: true + schema: + type: string + style: simple + - explode: false + in: path + name: bytes + required: true + schema: + format: byte + type: string + style: simple + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/header: + get: + operationId: headerParams + parameters: + - explode: false + in: header + name: X-Plain + required: false + schema: + type: string + style: simple + - explode: false + in: header + name: X-Byte + required: false + schema: + format: byte + type: string + style: simple + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/cookie: + get: + operationId: cookieParams + parameters: + - explode: true + in: cookie + name: plain + required: false + schema: + type: string + style: form + - explode: true + in: cookie + name: bytes + required: false + schema: + format: byte + type: string + style: form + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/form: + post: + operationId: formParams + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: "#/components/schemas/formParams_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/x-www-form-urlencoded + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/simple: + post: + operationId: multipartSimple + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartSimple_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/simple-validated: + post: + operationId: multipartSimpleValidated + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartSimple_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/files: + post: + operationId: multipartFileArray + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartFileArray_request" + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/mixed: + post: + operationId: multipartMixed + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartMixed_request" + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/json: + post: + operationId: jsonBody + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/formParams_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/json + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/binary: + post: + operationId: binaryBody + requestBody: + content: + application/octet-stream: + schema: + format: binary + type: string + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/octet-stream + x-accepts: + - application/json + x-tags: + - tag: coverage +components: + schemas: + MultipartMixedStatus: + enum: + - ALLOWED + - IN_PROGRESS + - REJECTED + type: string + MultipartMixedRequestMarker: + properties: + name: + type: string + priority: + format: int32 + type: integer + active: + type: boolean + required: + - name + type: object + formParams_request: + properties: + plain: + type: string + bytes: + format: byte + type: string + type: object + multipartSimple_request: + properties: + plain: + type: string + bytes: + format: byte + type: string + file: + format: binary + type: string + type: object + multipartFileArray_request: + properties: + files: + items: + format: binary + type: string + type: array + type: object + multipartMixed_request: + properties: + status: + $ref: "#/components/schemas/MultipartMixedStatus" + statusArray: + items: + $ref: "#/components/schemas/MultipartMixedStatus" + type: array + marker: + $ref: "#/components/schemas/MultipartMixedRequestMarker" + markerArray: + items: + $ref: "#/components/schemas/MultipartMixedRequestMarker" + type: array + file: + format: binary + type: string + required: + - file + - status + type: object diff --git a/samples/client/others/csharp-complex-files/api/openapi.yaml b/samples/client/others/csharp-complex-files/api/openapi.yaml index 7cb9e35505e7..bc671ba54e4e 100644 --- a/samples/client/others/csharp-complex-files/api/openapi.yaml +++ b/samples/client/others/csharp-complex-files/api/openapi.yaml @@ -57,6 +57,25 @@ components: - REJECTED example: REJECTED type: string + MultipartMixedRequestMarker: + description: Marker metadata sent as JSON part in multipart request + properties: + name: + description: Marker name + example: example-marker + type: string + priority: + description: Optional priority + example: 10 + format: int32 + type: integer + active: + description: Whether the marker is active + example: true + type: boolean + required: + - name + type: object multipartArray_request: properties: files: @@ -85,6 +104,11 @@ components: $ref: "#/components/schemas/MultipartMixedStatus" marker: $ref: "#/components/schemas/multipartMixed_request_marker" + markerArray: + description: array of objects + items: + $ref: "#/components/schemas/MultipartMixedRequestMarker" + type: array file: description: a file format: binary diff --git a/samples/client/others/csharp-complex-files/docs/MultipartApi.md b/samples/client/others/csharp-complex-files/docs/MultipartApi.md index 23628f526032..294c2b9fcab1 100644 --- a/samples/client/others/csharp-complex-files/docs/MultipartApi.md +++ b/samples/client/others/csharp-complex-files/docs/MultipartApi.md @@ -95,7 +95,7 @@ No authorization required # **MultipartMixed** -> void MultipartMixed (MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = null, List statusArray = null) +> void MultipartMixed (MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = null, List markerArray = null, List statusArray = null) @@ -121,11 +121,12 @@ namespace Example var status = (MultipartMixedStatus) "ALLOWED"; // MultipartMixedStatus | var file = new System.IO.MemoryStream(System.IO.File.ReadAllBytes("/path/to/file.txt")); // System.IO.Stream | a file var marker = new MultipartMixedRequestMarker(); // MultipartMixedRequestMarker | (optional) + var markerArray = new List(); // List | array of objects (optional) var statusArray = new List(); // List | (optional) try { - apiInstance.MultipartMixed(status, file, marker, statusArray); + apiInstance.MultipartMixed(status, file, marker, markerArray, statusArray); } catch (ApiException e) { @@ -144,7 +145,7 @@ This returns an ApiResponse object which contains the response data, status code ```csharp try { - apiInstance.MultipartMixedWithHttpInfo(status, file, marker, statusArray); + apiInstance.MultipartMixedWithHttpInfo(status, file, marker, markerArray, statusArray); } catch (ApiException e) { @@ -161,6 +162,7 @@ catch (ApiException e) | **status** | **MultipartMixedStatus** | | | | **file** | **System.IO.Stream****System.IO.Stream** | a file | | | **marker** | [**MultipartMixedRequestMarker**](MultipartMixedRequestMarker.md) | | [optional] | +| **markerArray** | [**List<MultipartMixedRequestMarker>**](MultipartMixedRequestMarker.md) | array of objects | [optional] | | **statusArray** | [**List<MultipartMixedStatus>**](MultipartMixedStatus.md) | | [optional] | ### Return type diff --git a/samples/client/others/csharp-complex-files/docs/MultipartMixedRequest.md b/samples/client/others/csharp-complex-files/docs/MultipartMixedRequest.md index d00f722a3542..8f6da65c6bb4 100644 --- a/samples/client/others/csharp-complex-files/docs/MultipartMixedRequest.md +++ b/samples/client/others/csharp-complex-files/docs/MultipartMixedRequest.md @@ -6,6 +6,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Status** | **MultipartMixedStatus** | | **Marker** | [**MultipartMixedRequestMarker**](MultipartMixedRequestMarker.md) | | [optional] +**MarkerArray** | [**List<MultipartMixedRequestMarker>**](MultipartMixedRequestMarker.md) | array of objects | [optional] **File** | **System.IO.Stream** | a file | **StatusArray** | [**List<MultipartMixedStatus>**](MultipartMixedStatus.md) | | [optional] diff --git a/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs b/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs index 5e305e7c4bc6..7c57e0d4cb4d 100644 --- a/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs +++ b/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs @@ -59,10 +59,11 @@ public interface IMultipartApiSync : IApiAccessor /// /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// - void MultipartMixed(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0); + void MultipartMixed(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0); /// /// @@ -74,10 +75,11 @@ public interface IMultipartApiSync : IApiAccessor /// /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// ApiResponse of Object(void) - ApiResponse MultipartMixedWithHttpInfo(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0); + ApiResponse MultipartMixedWithHttpInfo(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0); /// /// /// @@ -145,11 +147,12 @@ public interface IMultipartApiAsync : IApiAccessor /// /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// Cancellation Token to cancel the request. /// Task of void - System.Threading.Tasks.Task MultipartMixedAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default); + System.Threading.Tasks.Task MultipartMixedAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default); /// /// @@ -161,11 +164,12 @@ public interface IMultipartApiAsync : IApiAccessor /// /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// Cancellation Token to cancel the request. /// Task of ApiResponse - System.Threading.Tasks.Task> MultipartMixedWithHttpInfoAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default); + System.Threading.Tasks.Task> MultipartMixedWithHttpInfoAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default); /// /// /// @@ -461,12 +465,13 @@ public async System.Threading.Tasks.Task MultipartArrayAsync(List /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// - public void MultipartMixed(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0) + public void MultipartMixed(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0) { - MultipartMixedWithHttpInfo(status, file, marker, statusArray); + MultipartMixedWithHttpInfo(status, file, marker, markerArray, statusArray); } /// @@ -476,10 +481,11 @@ public void MultipartMixed(MultipartMixedStatus status, System.IO.Stream file, M /// /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// ApiResponse of Object(void) - public Org.OpenAPITools.Client.ApiResponse MultipartMixedWithHttpInfo(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0) + public Org.OpenAPITools.Client.ApiResponse MultipartMixedWithHttpInfo(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0) { // verify the required parameter 'file' is set if (file == null) @@ -515,6 +521,10 @@ public Org.OpenAPITools.Client.ApiResponse MultipartMixedWithHttpInfo(Mu { localVarRequestOptions.FormParameters.Add("marker", localVarMultipartFormData ? Org.OpenAPITools.Client.ClientUtils.ParameterToString(marker) : Org.OpenAPITools.Client.ClientUtils.Serialize(marker)); // form parameter } + if (markerArray != null) + { + localVarRequestOptions.FormParameters.Add("markerArray", localVarMultipartFormData ? Org.OpenAPITools.Client.ClientUtils.ParameterToString(markerArray) : Org.OpenAPITools.Client.ClientUtils.Serialize(markerArray)); // form parameter + } localVarRequestOptions.FileParameters.Add("file", file); if (statusArray != null) { @@ -546,13 +556,14 @@ public Org.OpenAPITools.Client.ApiResponse MultipartMixedWithHttpInfo(Mu /// /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// Cancellation Token to cancel the request. /// Task of void - public async System.Threading.Tasks.Task MultipartMixedAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default) + public async System.Threading.Tasks.Task MultipartMixedAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default) { - await MultipartMixedWithHttpInfoAsync(status, file, marker, statusArray, operationIndex, cancellationToken).ConfigureAwait(false); + await MultipartMixedWithHttpInfoAsync(status, file, marker, markerArray, statusArray, operationIndex, cancellationToken).ConfigureAwait(false); } /// @@ -562,11 +573,12 @@ public async System.Threading.Tasks.Task MultipartMixedAsync(MultipartMixedStatu /// /// a file /// (optional) + /// array of objects (optional) /// (optional) /// Index associated with the operation. /// Cancellation Token to cancel the request. /// Task of ApiResponse - public async System.Threading.Tasks.Task> MultipartMixedWithHttpInfoAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default) + public async System.Threading.Tasks.Task> MultipartMixedWithHttpInfoAsync(MultipartMixedStatus status, System.IO.Stream file, MultipartMixedRequestMarker marker = default, List markerArray = default, List statusArray = default, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default) { // verify the required parameter 'file' is set if (file == null) @@ -602,6 +614,10 @@ public async System.Threading.Tasks.Task MultipartMixedAsync(MultipartMixedStatu { localVarRequestOptions.FormParameters.Add("marker", Org.OpenAPITools.Client.ClientUtils.Serialize(marker)); // form parameter } + if (markerArray != null) + { + localVarRequestOptions.FormParameters.Add("markerArray", Org.OpenAPITools.Client.ClientUtils.Serialize(markerArray)); // form parameter + } localVarRequestOptions.FileParameters.Add("file", file); if (statusArray != null) { diff --git a/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs b/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs index 17a5fc53f5ef..9d2dcd9a1627 100644 --- a/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs +++ b/samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs @@ -48,9 +48,10 @@ protected MultipartMixedRequest() { } /// /// status (required). /// marker. + /// array of objects. /// a file (required). /// statusArray. - public MultipartMixedRequest(MultipartMixedStatus status = default, MultipartMixedRequestMarker marker = default, System.IO.Stream file = default, List statusArray = default) + public MultipartMixedRequest(MultipartMixedStatus status = default, MultipartMixedRequestMarker marker = default, List markerArray = default, System.IO.Stream file = default, List statusArray = default) { this.Status = status; // to ensure "file" is required (not null) @@ -60,6 +61,7 @@ public MultipartMixedRequest(MultipartMixedStatus status = default, MultipartMix } this.File = file; this.Marker = marker; + this.MarkerArray = markerArray; this.StatusArray = statusArray; } @@ -69,6 +71,13 @@ public MultipartMixedRequest(MultipartMixedStatus status = default, MultipartMix [DataMember(Name = "marker", EmitDefaultValue = false)] public MultipartMixedRequestMarker Marker { get; set; } + /// + /// array of objects + /// + /// array of objects + [DataMember(Name = "markerArray", EmitDefaultValue = false)] + public List MarkerArray { get; set; } + /// /// a file /// @@ -92,6 +101,7 @@ public override string ToString() sb.Append("class MultipartMixedRequest {\n"); sb.Append(" Status: ").Append(Status).Append("\n"); sb.Append(" Marker: ").Append(Marker).Append("\n"); + sb.Append(" MarkerArray: ").Append(MarkerArray).Append("\n"); sb.Append(" File: ").Append(File).Append("\n"); sb.Append(" StatusArray: ").Append(StatusArray).Append("\n"); sb.Append("}\n"); @@ -141,6 +151,10 @@ public override int GetHashCode() { hashCode = (hashCode * 59) + this.Marker.GetHashCode(); } + if (this.MarkerArray != null) + { + hashCode = (hashCode * 59) + this.MarkerArray.GetHashCode(); + } if (this.File != null) { hashCode = (hashCode * 59) + this.File.GetHashCode(); diff --git a/samples/client/petstore/spring-http-interface-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java b/samples/client/petstore/spring-http-interface-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java index bea5db699e3f..dca9125effd6 100644 --- a/samples/client/petstore/spring-http-interface-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/client/petstore/spring-http-interface-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java @@ -216,7 +216,7 @@ void testEndpointParameters( @RequestParam(value = "number", required = true) BigDecimal number, @RequestParam(value = "double", required = true) Double _double, @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @RequestParam(value = "byte", required = true) byte[] _byte, + @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @RequestParam(value = "integer", required = false) Integer integer, @RequestParam(value = "int32", required = false) Integer int32, @RequestParam(value = "int64", required = false) Long int64, @@ -259,7 +259,7 @@ void testEnumParameters( @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @RequestParam(value = "enum_form_string", required = false) String enumFormString ); diff --git a/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java b/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java index 04a9124859d4..f5605756718b 100644 --- a/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java @@ -217,20 +217,20 @@ Mono testClientModel( contentType = "application/x-www-form-urlencoded" ) Mono testEndpointParameters( - @RequestPart(value = "number", required = true) BigDecimal number, - @RequestPart(value = "double", required = true) Double _double, - @RequestPart(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @RequestPart(value = "byte", required = true) byte[] _byte, - @RequestPart(value = "integer", required = false) Integer integer, - @RequestPart(value = "int32", required = false) Integer int32, - @RequestPart(value = "int64", required = false) Long int64, - @RequestPart(value = "float", required = false) Float _float, - @RequestPart(value = "string", required = false) String string, + @RequestParam(value = "number", required = true) BigDecimal number, + @RequestParam(value = "double", required = true) Double _double, + @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, + @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, + @RequestParam(value = "integer", required = false) Integer integer, + @RequestParam(value = "int32", required = false) Integer int32, + @RequestParam(value = "int64", required = false) Long int64, + @RequestParam(value = "float", required = false) Float _float, + @RequestParam(value = "string", required = false) String string, @RequestPart(value = "binary", required = false) Part binary, - @RequestPart(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, - @RequestPart(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, - @RequestPart(value = "password", required = false) String password, - @RequestPart(value = "callback", required = false) String paramCallback + @RequestParam(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, + @RequestParam(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, + @RequestParam(value = "password", required = false) String password, + @RequestParam(value = "callback", required = false) String paramCallback ); @@ -263,8 +263,8 @@ Mono testEnumParameters( @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, - @RequestPart(value = "enum_form_string", required = false) String enumFormString + @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, + @RequestParam(value = "enum_form_string", required = false) String enumFormString ); @@ -331,8 +331,8 @@ Mono testInlineAdditionalProperties( contentType = "application/x-www-form-urlencoded" ) Mono testJsonFormData( - @RequestPart(value = "param", required = true) String param, - @RequestPart(value = "param2", required = true) String param2 + @RequestParam(value = "param", required = true) String param, + @RequestParam(value = "param2", required = true) String param2 ); diff --git a/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java b/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java index ecd126897323..179164b1ac10 100644 --- a/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java +++ b/samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java @@ -186,8 +186,8 @@ Mono updatePet( ) Mono updatePetWithForm( @PathVariable("petId") Long petId, - @RequestPart(value = "name", required = false) String name, - @RequestPart(value = "status", required = false) String status + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "status", required = false) String status ); diff --git a/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/FakeApi.java b/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/FakeApi.java index 0fefc031ea6d..ec1d768f7ac5 100644 --- a/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/FakeApi.java @@ -208,20 +208,20 @@ Mono> testClientModel( contentType = "application/x-www-form-urlencoded" ) Mono> testEndpointParameters( - @RequestPart(value = "number", required = true) BigDecimal number, - @RequestPart(value = "double", required = true) Double _double, - @RequestPart(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @RequestPart(value = "byte", required = true) byte[] _byte, - @RequestPart(value = "integer", required = false) Integer integer, - @RequestPart(value = "int32", required = false) Integer int32, - @RequestPart(value = "int64", required = false) Long int64, - @RequestPart(value = "float", required = false) Float _float, - @RequestPart(value = "string", required = false) String string, + @RequestParam(value = "number", required = true) BigDecimal number, + @RequestParam(value = "double", required = true) Double _double, + @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, + @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, + @RequestParam(value = "integer", required = false) Integer integer, + @RequestParam(value = "int32", required = false) Integer int32, + @RequestParam(value = "int64", required = false) Long int64, + @RequestParam(value = "float", required = false) Float _float, + @RequestParam(value = "string", required = false) String string, @RequestPart(value = "binary", required = false) Part binary, - @RequestPart(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, - @RequestPart(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, - @RequestPart(value = "password", required = false) String password, - @RequestPart(value = "callback", required = false) String paramCallback + @RequestParam(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, + @RequestParam(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, + @RequestParam(value = "password", required = false) String password, + @RequestParam(value = "callback", required = false) String paramCallback ); @@ -253,8 +253,8 @@ Mono> testEnumParameters( @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, - @RequestPart(value = "enum_form_string", required = false) String enumFormString + @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, + @RequestParam(value = "enum_form_string", required = false) String enumFormString ); @@ -318,8 +318,8 @@ Mono> testInlineAdditionalProperties( contentType = "application/x-www-form-urlencoded" ) Mono> testJsonFormData( - @RequestPart(value = "param", required = true) String param, - @RequestPart(value = "param2", required = true) String param2 + @RequestParam(value = "param", required = true) String param, + @RequestParam(value = "param2", required = true) String param2 ); diff --git a/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/PetApi.java b/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/PetApi.java index fd584ea831df..30dc9521db32 100644 --- a/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/PetApi.java +++ b/samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/PetApi.java @@ -178,8 +178,8 @@ Mono> updatePet( ) Mono> updatePetWithForm( @PathVariable("petId") Long petId, - @RequestPart(value = "name", required = false) String name, - @RequestPart(value = "status", required = false) String status + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "status", required = false) String status ); diff --git a/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/api/FakeApi.java b/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/api/FakeApi.java index fc8aa14fdf11..94dc809581c7 100644 --- a/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/api/FakeApi.java @@ -207,7 +207,7 @@ ResponseEntity testEndpointParameters( @RequestParam(value = "number", required = true) BigDecimal number, @RequestParam(value = "double", required = true) Double _double, @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @RequestParam(value = "byte", required = true) byte[] _byte, + @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @RequestParam(value = "integer", required = false) Integer integer, @RequestParam(value = "int32", required = false) Integer int32, @RequestParam(value = "int64", required = false) Long int64, @@ -249,7 +249,7 @@ ResponseEntity testEnumParameters( @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @RequestParam(value = "enum_form_string", required = false) String enumFormString ); diff --git a/samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/FakeApi.java b/samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/FakeApi.java index 2b5414dd0e62..132f9d70de8e 100644 --- a/samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/FakeApi.java @@ -315,7 +315,7 @@ ResponseEntity testEndpointParameters( @Parameter(name = "number", description = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @Parameter(name = "double", description = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @Parameter(name = "pattern_without_delimiter", description = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @Parameter(name = "integer", description = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @Parameter(name = "int32", description = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @Parameter(name = "int64", description = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -367,7 +367,7 @@ ResponseEntity testEnumParameters( @Parameter(name = "enum_query_string", description = "Query parameter enum test (string)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @Parameter(name = "enum_query_integer", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @Parameter(name = "enum_query_double", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @Parameter(name = "enum_form_string", description = "Form parameter enum test (string)") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ); diff --git a/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java b/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java index 565ffd66dc3f..9182ad4c669e 100644 --- a/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java @@ -364,7 +364,7 @@ default ResponseEntity testEndpointParameters( @Parameter(name = "number", description = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @Parameter(name = "double", description = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @Parameter(name = "pattern_without_delimiter", description = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @Parameter(name = "integer", description = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @Parameter(name = "int32", description = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @Parameter(name = "int64", description = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -418,7 +418,7 @@ default ResponseEntity testEnumParameters( @Parameter(name = "enum_query_string", description = "Query parameter enum test (string)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @Parameter(name = "enum_query_integer", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @Parameter(name = "enum_query_double", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @Parameter(name = "enum_form_string", description = "Form parameter enum test (string)") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return getDelegate().testEnumParameters(enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString); diff --git a/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java b/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java index da19eea506c4..e9843810956f 100644 --- a/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java +++ b/samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java @@ -207,7 +207,7 @@ default ResponseEntity testClientModel(Client client) { default ResponseEntity testEndpointParameters(BigDecimal number, Double _double, String patternWithoutDelimiter, - byte[] _byte, + String _byte, Integer integer, Integer int32, Long int64, diff --git a/samples/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java b/samples/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java index af328fa7ff70..638b2fb89783 100644 --- a/samples/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java @@ -404,7 +404,7 @@ default ResponseEntity testEndpointParameters( @Parameter(name = "number", description = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @Parameter(name = "double", description = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @Parameter(name = "pattern_without_delimiter", description = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @Parameter(name = "integer", description = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @Parameter(name = "int32", description = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @Parameter(name = "int64", description = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -459,7 +459,7 @@ default ResponseEntity testEnumParameters( @Parameter(name = "enum_query_string", description = "Query parameter enum test (string)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @Parameter(name = "enum_query_integer", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @Parameter(name = "enum_query_double", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @Parameter(name = "enum_form_string", description = "Form parameter enum test (string)") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/PetApiTest.java b/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/PetApiTest.java index db242ade0a0a..e55f136c415e 100644 --- a/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/PetApiTest.java +++ b/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/PetApiTest.java @@ -1,5 +1,5 @@ -/** -* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.11.0-SNAPSHOT). +/* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.20.0-SNAPSHOT). * https://openapi-generator.tech * Do not edit the class manually. */ diff --git a/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/StoreApiTest.java b/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/StoreApiTest.java index 2316853508bc..249efd225573 100644 --- a/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/StoreApiTest.java +++ b/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/StoreApiTest.java @@ -1,5 +1,5 @@ -/** -* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.11.0-SNAPSHOT). +/* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.20.0-SNAPSHOT). * https://openapi-generator.tech * Do not edit the class manually. */ diff --git a/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/UserApiTest.java b/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/UserApiTest.java index 9d71548a6d7f..199e78ab9152 100644 --- a/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/UserApiTest.java +++ b/samples/server/petstore/java-camel/src/test/java/org/openapitools/api/UserApiTest.java @@ -1,5 +1,5 @@ -/** -* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.11.0-SNAPSHOT). +/* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.20.0-SNAPSHOT). * https://openapi-generator.tech * Do not edit the class manually. */ diff --git a/samples/server/petstore/spring-boot-defaultInterface-unhandledExcp/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/spring-boot-defaultInterface-unhandledExcp/src/main/java/org/openapitools/api/FakeApi.java index 458409c67391..64ba48c3c47f 100644 --- a/samples/server/petstore/spring-boot-defaultInterface-unhandledExcp/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/spring-boot-defaultInterface-unhandledExcp/src/main/java/org/openapitools/api/FakeApi.java @@ -343,7 +343,7 @@ ResponseEntity testEndpointParameters( @Parameter(name = "number", description = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @Parameter(name = "double", description = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @Parameter(name = "pattern_without_delimiter", description = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @Parameter(name = "integer", description = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @Parameter(name = "int32", description = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @Parameter(name = "int64", description = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -395,7 +395,7 @@ ResponseEntity testEnumParameters( @Parameter(name = "enum_query_string", description = "Query parameter enum test (string)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @Parameter(name = "enum_query_integer", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @Parameter(name = "enum_query_double", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @Parameter(name = "enum_form_string", description = "Form parameter enum test (string)") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) throws Exception; diff --git a/samples/server/petstore/springboot-beanvalidation-no-nullable/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-beanvalidation-no-nullable/src/main/java/org/openapitools/api/FakeApi.java index 0ea604f8b3a9..7b95f6ff88ea 100644 --- a/samples/server/petstore/springboot-beanvalidation-no-nullable/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-beanvalidation-no-nullable/src/main/java/org/openapitools/api/FakeApi.java @@ -396,7 +396,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -451,7 +451,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-beanvalidation/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-beanvalidation/src/main/java/org/openapitools/api/FakeApi.java index 0ea604f8b3a9..7b95f6ff88ea 100644 --- a/samples/server/petstore/springboot-beanvalidation/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-beanvalidation/src/main/java/org/openapitools/api/FakeApi.java @@ -396,7 +396,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -451,7 +451,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-builtin-validation/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-builtin-validation/src/main/java/org/openapitools/api/FakeApi.java index 6a98cfc50239..4a165d2c5f74 100644 --- a/samples/server/petstore/springboot-builtin-validation/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-builtin-validation/src/main/java/org/openapitools/api/FakeApi.java @@ -396,7 +396,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -451,7 +451,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator-ignore b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator/FILES b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator/FILES new file mode 100644 index 000000000000..7e2ea15534aa --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator/FILES @@ -0,0 +1,8 @@ +README.md +pom.xml +src/main/java/org/openapitools/api/ApiUtil.java +src/main/java/org/openapitools/api/CoverageApi.java +src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java +src/main/java/org/openapitools/model/FormParamsRequest.java +src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java +src/main/java/org/openapitools/model/MultipartMixedStatus.java diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator/VERSION b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/README.md b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/README.md new file mode 100644 index 000000000000..d43a1de307df --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/README.md @@ -0,0 +1,27 @@ + +# OpenAPI generated API stub + +Spring Framework stub + + +## Overview +This code was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. +By using the [OpenAPI-Spec](https://openapis.org), you can easily generate an API stub. +This is an example of building API stub interfaces in Java using the Spring framework. + +The stubs generated can be used in your existing Spring-MVC or Spring-Boot application to create controller endpoints +by adding ```@Controller``` classes that implement the interface. Eg: +```java +@Controller +public class PetController implements PetApi { +// implement all PetApi methods +} +``` + +You can also use the interface to create [Spring-Cloud Feign clients](http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign-inheritance).Eg: +```java +@FeignClient(name="pet", url="http://petstore.swagger.io/v2") +public interface PetClient extends PetApi { + +} +``` diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/pom.xml b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/pom.xml new file mode 100644 index 000000000000..439b85f5ce56 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/pom.xml @@ -0,0 +1,88 @@ + + 4.0.0 + org.openapitools + springboot + jar + springboot + 1.0.0-SNAPSHOT + + 1.8 + ${java.version} + ${java.version} + UTF-8 + 1.6.14 + 5.3.1 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.15 + + + + src/main/java + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.data + spring-data-commons + + + + org.springdoc + springdoc-openapi-webflux-ui + ${springdoc.version} + + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + org.openapitools + jackson-databind-nullable + 0.2.8 + + + + org.springframework.boot + spring-boot-starter-validation + + + com.fasterxml.jackson.core + jackson-databind + + + org.springframework.boot + spring-boot-starter-test + test + + + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/OpenApiGeneratorApplication.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/OpenApiGeneratorApplication.java new file mode 100644 index 000000000000..97252a8a9402 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/OpenApiGeneratorApplication.java @@ -0,0 +1,30 @@ +package org.openapitools; + +import com.fasterxml.jackson.databind.Module; +import org.openapitools.jackson.nullable.JsonNullableModule; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator; + +@SpringBootApplication( + nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class +) +@ComponentScan( + basePackages = {"org.openapitools", "org.openapitools.api" , "org.openapitools.configuration"}, + nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class +) +public class OpenApiGeneratorApplication { + + public static void main(String[] args) { + SpringApplication.run(OpenApiGeneratorApplication.class, args); + } + + @Bean(name = "org.openapitools.OpenApiGeneratorApplication.jsonNullableModule") + public Module jsonNullableModule() { + return new JsonNullableModule(); + } + +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/RFC3339DateFormat.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/RFC3339DateFormat.java new file mode 100644 index 000000000000..bcd3936d8b34 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/RFC3339DateFormat.java @@ -0,0 +1,38 @@ +package org.openapitools; + +import com.fasterxml.jackson.databind.util.StdDateFormat; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +public class RFC3339DateFormat extends DateFormat { + private static final long serialVersionUID = 1L; + private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); + + private final StdDateFormat fmt = new StdDateFormat() + .withTimeZone(TIMEZONE_Z) + .withColonInTimeZone(true); + + public RFC3339DateFormat() { + this.calendar = new GregorianCalendar(); + } + + @Override + public Date parse(String source, ParsePosition pos) { + return fmt.parse(source, pos); + } + + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + return fmt.format(date, toAppendTo, fieldPosition); + } + + @Override + public Object clone() { + return this; + } +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/ApiUtil.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/ApiUtil.java new file mode 100644 index 000000000000..7ed3b0ab28d9 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/ApiUtil.java @@ -0,0 +1,20 @@ +package org.openapitools.api; + +import java.nio.charset.StandardCharsets; +import org.springframework.core.io.buffer.DefaultDataBuffer; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +public class ApiUtil { + public static Mono getExampleResponse(ServerWebExchange exchange, MediaType mediaType, String example) { + ServerHttpResponse response = exchange.getResponse(); + response.getHeaders().setContentType(mediaType); + + byte[] exampleBytes = example.getBytes(StandardCharsets.UTF_8); + DefaultDataBuffer data = new DefaultDataBufferFactory().wrap(exampleBytes); + return response.writeWith(Mono.just(data)); + } +} diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApi.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApi.java new file mode 100644 index 000000000000..df4a1aa669ac --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApi.java @@ -0,0 +1,398 @@ +/* + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.20.0-SNAPSHOT). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package org.openapitools.api; + +import org.openapitools.model.FormParamsRequest; +import org.openapitools.model.MultipartMixedRequestMarker; +import org.openapitools.model.MultipartMixedStatus; +import org.springframework.lang.Nullable; +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import org.springframework.http.codec.multipart.Part; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import javax.annotation.Generated; + +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +@Validated +@Tag(name = "coverage", description = "the coverage API") +public interface CoverageApi { + + String PATH_BINARY_BODY = "/coverage/binary"; + /** + * POST /coverage/binary + * + * @param body (required) + * @return No content (status code 204) + */ + @Operation( + operationId = "binaryBody", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_BINARY_BODY, + consumes = { "application/octet-stream" } + ) + default Mono> binaryBody( + @Parameter(name = "body", description = "", required = true) @Valid @RequestBody Mono body, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(body).then(Mono.empty()); + + } + + + String PATH_COOKIE_PARAMS = "/coverage/cookie"; + /** + * GET /coverage/cookie + * + * @param plain (optional) + * @param bytes (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "cookieParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_COOKIE_PARAMS + ) + default Mono> cookieParams( + @Parameter(name = "plain", description = "", in = ParameterIn.COOKIE) @CookieValue(name = "plain", required = false) @Nullable String plain, + @Parameter(name = "bytes", description = "", in = ParameterIn.COOKIE) @CookieValue(name = "bytes", required = false) @Nullable String bytes /* base64 encoded binary */, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_FORM_PARAMS = "/coverage/form"; + /** + * POST /coverage/form + * + * @param plain (optional) + * @param bytes (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "formParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_FORM_PARAMS, + consumes = { "application/x-www-form-urlencoded" } + ) + default Mono> formParams( + @Parameter(name = "plain", description = "") @Valid @RequestParam(value = "plain", required = false) String plain, + @Parameter(name = "bytes", description = "") @Valid @RequestParam(value = "bytes", required = false) String bytes /* base64 encoded binary */, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_HEADER_PARAMS = "/coverage/header"; + /** + * GET /coverage/header + * + * @param xPlain (optional) + * @param xByte (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "headerParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_HEADER_PARAMS + ) + default Mono> headerParams( + @Parameter(name = "X-Plain", description = "", in = ParameterIn.HEADER) @RequestHeader(value = "X-Plain", required = false) @Nullable String xPlain, + @Parameter(name = "X-Byte", description = "", in = ParameterIn.HEADER) @RequestHeader(value = "X-Byte", required = false) @Nullable String xByte /* base64 encoded binary */, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_JSON_BODY = "/coverage/json"; + /** + * POST /coverage/json + * + * @param formParamsRequest (required) + * @return No content (status code 204) + */ + @Operation( + operationId = "jsonBody", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_JSON_BODY, + consumes = { "application/json" } + ) + default Mono> jsonBody( + @Parameter(name = "FormParamsRequest", description = "", required = true) @Valid @RequestBody Mono formParamsRequest, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(formParamsRequest).then(Mono.empty()); + + } + + + String PATH_MULTIPART_FILE_ARRAY = "/coverage/multipart/files"; + /** + * POST /coverage/multipart/files + * + * @param files (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartFileArray", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_FILE_ARRAY, + consumes = { "multipart/form-data" } + ) + default Mono> multipartFileArray( + @Parameter(name = "files", description = "") @RequestPart(value = "files", required = false) Flux files, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_MULTIPART_MIXED = "/coverage/multipart/mixed"; + /** + * POST /coverage/multipart/mixed + * + * @param status (required) + * @param file (required) + * @param statusArray (optional) + * @param marker (optional) + * @param markerArray (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartMixed", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_MIXED, + consumes = { "multipart/form-data" } + ) + default Mono> multipartMixed( + @Parameter(name = "status", description = "", required = true) @Valid @RequestPart(value = "status", required = true) String /* MultipartMixedStatus */ status, + @Parameter(name = "file", description = "", required = true) @RequestPart(value = "file", required = true) Part file, + @Parameter(name = "statusArray", description = "") @Valid @RequestPart(value = "statusArray", required = false) Flux /* List */ statusArray, + @Parameter(name = "marker", description = "") @Valid @RequestPart(value = "marker", required = false) MultipartMixedRequestMarker marker, + @Parameter(name = "markerArray", description = "") @Valid @RequestPart(value = "markerArray", required = false) List<@Valid MultipartMixedRequestMarker> markerArray, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_MULTIPART_SIMPLE = "/coverage/multipart/simple"; + /** + * POST /coverage/multipart/simple + * + * @param plain (optional) + * @param bytes (optional) + * @param file (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartSimple", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_SIMPLE, + consumes = { "multipart/form-data" } + ) + default Mono> multipartSimple( + @Parameter(name = "plain", description = "") @Valid @RequestPart(value = "plain", required = false) String plain, + @Parameter(name = "bytes", description = "") @Valid @RequestPart(value = "bytes", required = false) String bytes /* base64 encoded binary */, + @Parameter(name = "file", description = "") @RequestPart(value = "file", required = false) Part file, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_MULTIPART_SIMPLE_VALIDATED = "/coverage/multipart/simple-validated"; + /** + * POST /coverage/multipart/simple-validated + * + * @param plain (optional) + * @param bytes (optional) + * @param file (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartSimpleValidated", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_SIMPLE_VALIDATED, + consumes = { "multipart/form-data" } + ) + default Mono> multipartSimpleValidated( + @Parameter(name = "plain", description = "") @Valid @RequestPart(value = "plain", required = false) String plain, + @Parameter(name = "bytes", description = "") @Valid @RequestPart(value = "bytes", required = false) String bytes /* base64 encoded binary */, + @Parameter(name = "file", description = "") @RequestPart(value = "file", required = false) Part file, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_PATH_PARAMS = "/coverage/path/{plain}/{bytes}"; + /** + * GET /coverage/path/{plain}/{bytes} + * + * @param plain (required) + * @param bytes (required) + * @return No content (status code 204) + */ + @Operation( + operationId = "pathParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_PATH_PARAMS + ) + default Mono> pathParams( + @NotNull @Parameter(name = "plain", description = "", required = true, in = ParameterIn.PATH) @PathVariable("plain") String plain, + @NotNull @Parameter(name = "bytes", description = "", required = true, in = ParameterIn.PATH) @PathVariable("bytes") String bytes /* base64 encoded binary */, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + + + String PATH_QUERY_PARAMS = "/coverage/query"; + /** + * GET /coverage/query + * + * @param plain (optional) + * @param bytes (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "queryParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_QUERY_PARAMS + ) + default Mono> queryParams( + @Parameter(name = "plain", description = "", in = ParameterIn.QUERY) @Valid @RequestParam(value = "plain", required = false) @Nullable String plain, + @Parameter(name = "bytes", description = "", in = ParameterIn.QUERY) @Valid @RequestParam(value = "bytes", required = false) @Nullable String bytes /* base64 encoded binary */, + @Parameter(hidden = true) final ServerWebExchange exchange + ) { + Mono result = Mono.empty(); + exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED); + return result.then(Mono.empty()); + + } + +} diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java new file mode 100644 index 000000000000..3e0edc078b84 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java @@ -0,0 +1,415 @@ +// manually created counterpart to unit tests. Do not delete! +package org.openapitools.api; + +import org.openapitools.model.FormParamsRequest; +import org.openapitools.model.MultipartMixedRequestMarker; +import org.openapitools.model.MultipartMixedStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.codec.multipart.Part; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.server.ServerWebExchange; + +@Controller +@RequestMapping("${openapi.multipartByteEdgeCaseCoverage.base-path:}") +public class CoverageApiTestControllerImpl implements CoverageApi { + + private static final Logger logger = LoggerFactory.getLogger(CoverageApiTestControllerImpl.class); + + // Expected content for binary data verification - matches test constants + private static final byte[] EXPECTED_BYTES = "hello".getBytes(StandardCharsets.UTF_8); + private static final String EXPECTED_BYTES_STRING = "hello"; + + private Mono verifyBytesContent(byte[] actual, String fieldName) { + if (!Arrays.equals(EXPECTED_BYTES, actual)) { + String actualString = new String(actual, StandardCharsets.UTF_8); + String errorMsg = fieldName + " content mismatch: expected '" + EXPECTED_BYTES_STRING + "', got '" + actualString + "'"; + logger.warn("Validation failed: {}", errorMsg); + return Mono.error(new IllegalArgumentException(errorMsg)); + } + logger.debug("Bytes verification passed for field: {}", fieldName); + return Mono.empty(); + } + + private Mono verifyBase64Content(String base64Value, String fieldName) { + try { + byte[] decoded = Base64.getDecoder().decode(base64Value); + logger.debug("Base64 decoded successfully for field: {}", fieldName); + return verifyBytesContent(decoded, fieldName); + } catch (IllegalArgumentException e) { + logger.warn("Invalid base64 in field {}: {}", fieldName, e.getMessage()); + return Mono.error(new IllegalArgumentException("Invalid base64 in " + fieldName, e)); + } + } + + @Override + public Mono> binaryBody( + Mono body, + ServerWebExchange exchange + ) { + return body.flatMap(resource -> { + if (resource == null) { + return Mono.error(new IllegalArgumentException("body is required")); + } + return Mono.fromCallable(() -> { + try { + byte[] content = readAllBytes(resource.getInputStream()); + if (content.length == 0) { + throw new IllegalArgumentException("body content is empty"); + } + return content; + } catch (IOException e) { + throw new RuntimeException("Failed to read binary body", e); + } + }).flatMap(content -> verifyBytesContent(content, "body")); + }).then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + + private byte[] readAllBytes(InputStream inputStream) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[1024]; + while ((nRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + return buffer.toByteArray(); + } + + @Override + public Mono> cookieParams( + String plain, + String bytes, + ServerWebExchange exchange + ) { + if (bytes != null) { + return verifyBase64Content(bytes, "bytes") + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + return Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT)); + } + + @Override + public Mono> formParams( + String plain, + String bytes, + ServerWebExchange exchange + ) { + if (bytes != null) { + return verifyBase64Content(bytes, "bytes") + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + return Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT)); + } + + @Override + public Mono> headerParams( + String xPlain, + String xByte, + ServerWebExchange exchange + ) { + if (xByte != null) { + return verifyBase64Content(xByte, "X-Byte") + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + return Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT)); + } + + @Override + public Mono> jsonBody( + Mono formParamsRequest, + ServerWebExchange exchange + ) { + return formParamsRequest.flatMap(request -> { + if (request == null) { + return Mono.error(new IllegalArgumentException("formParamsRequest is required")); + } + byte[] bytes = request.getBytes(); + if (bytes != null) { + return verifyBytesContent(bytes, "bytes"); + } + return Mono.empty(); + }).then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + + @Override + public Mono> multipartFileArray( + Flux files, + ServerWebExchange exchange + ) { + // Expected content for each file in the array - matches test constants + String[] expectedContents = { "content1", "content2", "content3" }; + + if (files == null) { + return Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT)); + } + + return files.collectList().flatMap(partList -> { + return Flux.range(0, partList.size()) + .flatMap(i -> { + Part part = partList.get(i); + return part.content() + .collectList() + .flatMap(buffers -> { + byte[] content = new byte[buffers.stream().mapToInt(b -> b.readableByteCount()).sum()]; + int offset = 0; + for (DataBuffer buffer : buffers) { + int readable = buffer.readableByteCount(); + buffer.read(content, offset, readable); + offset += readable; + } + + if (content.length == 0) { + return Mono.error(new IllegalArgumentException("files[" + i + "] content is empty")); + } + + if (i < expectedContents.length) { + byte[] expected = expectedContents[i].getBytes(StandardCharsets.UTF_8); + if (!Arrays.equals(expected, content)) { + String actualString = new String(content, StandardCharsets.UTF_8); + return Mono.error(new IllegalArgumentException( + "files[" + i + "] content mismatch: expected '" + expectedContents[i] + "', got '" + actualString + "'")); + } + } + return Mono.empty(); + }); + }) + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))); + }).onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + + @Override + public Mono> multipartMixed( + String status, + Part file, + Flux statusArray, + MultipartMixedRequestMarker marker, + List markerArray, + ServerWebExchange exchange + ) { + if (status == null) { + return Mono.error(new IllegalArgumentException("status is required")); + } + if (file == null) { + return Mono.error(new IllegalArgumentException("file is required")); + } + + // Verify enum value is valid + MultipartMixedStatus enumStatus = MultipartMixedStatus.fromValue(status); + if (enumStatus == null) { + return Mono.error(new IllegalArgumentException("status value is invalid: " + status)); + } + String reconstructedStatus = enumStatus.getValue(); + if (reconstructedStatus == null || reconstructedStatus.isEmpty()) { + return Mono.error(new IllegalArgumentException("status value is invalid")); + } + + return file.content() + .collectList() + .flatMap(buffers -> { + byte[] fileContent = new byte[buffers.stream().mapToInt(b -> b.readableByteCount()).sum()]; + int offset = 0; + for (DataBuffer buffer : buffers) { + int readable = buffer.readableByteCount(); + buffer.read(fileContent, offset, readable); + offset += readable; + } + return verifyBytesContent(fileContent, "file"); + }) + .then(statusArray != null ? + statusArray.index() + .doOnNext(tuple -> { + long index = tuple.getT1(); + String statusValue = tuple.getT2(); + try { + MultipartMixedStatus enumValue = MultipartMixedStatus.fromValue(statusValue); + if (enumValue == null || enumValue.getValue() == null) { + throw new IllegalArgumentException("statusArray[" + index + "] contains invalid enum: " + statusValue); + } + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("statusArray[" + index + "] contains invalid enum: " + statusValue, e); + } + }) + .then() + : Mono.empty()) + .then(Mono.fromCallable(() -> { + + // Verify POJO fields + if (marker != null) { + String name = marker.getName(); + if (name == null) { + throw new IllegalArgumentException("marker.name is required"); + } + } + + // Verify POJO array fields + if (markerArray != null) { + for (int i = 0; i < markerArray.size(); i++) { + MultipartMixedRequestMarker m = markerArray.get(i); + String name = m.getName(); + if (name == null) { + throw new IllegalArgumentException("markerArray[" + i + "].name is required"); + } + } + } + return null; + })) + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + + @Override + public Mono> multipartSimple( + String plain, + String bytes, + Part file, + ServerWebExchange exchange + ) { + return Mono.fromCallable(() -> { + if (bytes != null) { + try { + byte[] decoded = Base64.getDecoder().decode(bytes); + if (!Arrays.equals(EXPECTED_BYTES, decoded)) { + String actualString = new String(decoded, StandardCharsets.UTF_8); + throw new IllegalArgumentException( + "bytes content mismatch: expected '" + EXPECTED_BYTES_STRING + "', got '" + actualString + "'"); + } + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid base64 in bytes", e); + } + } + return null; + }).then(file != null ? + file.content() + .collectList() + .then(Mono.empty()) + : Mono.empty()) + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + + @Override + public Mono> multipartSimpleValidated( + String plain, + String bytes, + Part file, + ServerWebExchange exchange + ) { + return Mono.fromCallable(() -> { + if (bytes != null) { + try { + byte[] decoded = Base64.getDecoder().decode(bytes); + if (!Arrays.equals(EXPECTED_BYTES, decoded)) { + String actualString = new String(decoded, StandardCharsets.UTF_8); + throw new IllegalArgumentException( + "bytes content mismatch: expected '" + EXPECTED_BYTES_STRING + "', got '" + actualString + "'"); + } + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid base64 in bytes", e); + } + } + return null; + }).then(file != null ? + file.content() + .collectList() + .flatMap(buffers -> { + byte[] fileContent = new byte[buffers.stream().mapToInt(b -> b.readableByteCount()).sum()]; + int offset = 0; + for (DataBuffer buffer : buffers) { + int readable = buffer.readableByteCount(); + buffer.read(fileContent, offset, readable); + offset += readable; + } + return verifyBytesContent(fileContent, "file"); + }).then() + : Mono.empty()) + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + + @Override + public Mono> pathParams( + String plain, + String bytes, + ServerWebExchange exchange + ) { + if (plain == null) { + return Mono.error(new IllegalArgumentException("plain is required")); + } + if (bytes == null) { + return Mono.error(new IllegalArgumentException("bytes is required")); + } + return verifyBase64Content(bytes, "bytes") + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + + @Override + public Mono> queryParams( + String plain, + String bytes, + ServerWebExchange exchange + ) { + if (bytes != null) { + return verifyBase64Content(bytes, "bytes") + .then(Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT))) + .onErrorResume(e -> { + exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Mono.error(e); + }); + } + return Mono.just(new ResponseEntity(HttpStatus.NO_CONTENT)); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java new file mode 100644 index 000000000000..7c174fb2fd4d --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java @@ -0,0 +1,29 @@ +package org.openapitools.configuration; + +import org.openapitools.model.MultipartMixedStatus; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; + +/** + * This class provides Spring Converter beans for the enum models in the OpenAPI specification. + * + * By default, Spring only converts primitive types to enums using Enum::valueOf, which can prevent + * correct conversion if the OpenAPI specification is using an `enumPropertyNaming` other than + * `original` or the specification has an integer enum. + */ +@Configuration(value = "org.openapitools.configuration.enumConverterConfiguration") +public class EnumConverterConfiguration { + + @Bean(name = "org.openapitools.configuration.EnumConverterConfiguration.multipartMixedStatusConverter") + Converter multipartMixedStatusConverter() { + return new Converter() { + @Override + public MultipartMixedStatus convert(String source) { + return MultipartMixedStatus.fromValue(source); + } + }; + } + +} diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/configuration/HomeController.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/configuration/HomeController.java new file mode 100644 index 000000000000..cf658246a9de --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/configuration/HomeController.java @@ -0,0 +1,29 @@ +package org.openapitools.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerResponse; +import java.net.URI; + +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; + +/** + * Home redirection to OpenAPI api documentation + */ +@Controller +public class HomeController { + + @Bean + RouterFunction index() { + return route( + GET("/"), + req -> ServerResponse.temporaryRedirect(URI.create("swagger-ui.html")).build() + ); + } + +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/FormParamsRequest.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/FormParamsRequest.java new file mode 100644 index 000000000000..45a6712a7e0f --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/FormParamsRequest.java @@ -0,0 +1,111 @@ +package org.openapitools.model; + +import java.net.URI; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import java.util.Arrays; +import org.springframework.lang.Nullable; +import org.openapitools.jackson.nullable.JsonNullable; +import java.time.OffsetDateTime; +import javax.validation.Valid; +import javax.validation.constraints.*; +import io.swagger.v3.oas.annotations.media.Schema; + + +import java.util.*; +import javax.annotation.Generated; + +/** + * FormParamsRequest + */ + +@JsonTypeName("formParams_request") +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +public class FormParamsRequest { + + private @Nullable String plain; + + private @Nullable byte[] bytes; + + public FormParamsRequest plain(@Nullable String plain) { + this.plain = plain; + return this; + } + + /** + * Get plain + * @return plain + */ + + @Schema(name = "plain", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("plain") + public @Nullable String getPlain() { + return plain; + } + + public void setPlain(@Nullable String plain) { + this.plain = plain; + } + + public FormParamsRequest bytes(@Nullable byte[] bytes) { + this.bytes = bytes; + return this; + } + + /** + * Get bytes + * @return bytes + */ + + @Schema(name = "bytes", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("bytes") + public @Nullable byte[] getBytes() { + return bytes; + } + + public void setBytes(@Nullable byte[] bytes) { + this.bytes = bytes; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FormParamsRequest formParamsRequest = (FormParamsRequest) o; + return Objects.equals(this.plain, formParamsRequest.plain) && + Arrays.equals(this.bytes, formParamsRequest.bytes); + } + + @Override + public int hashCode() { + return Objects.hash(plain, Arrays.hashCode(bytes)); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class FormParamsRequest {\n"); + sb.append(" plain: ").append(toIndentedString(plain)).append("\n"); + sb.append(" bytes: ").append(toIndentedString(bytes)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(@Nullable Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java new file mode 100644 index 000000000000..6f25fa78d166 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java @@ -0,0 +1,143 @@ +package org.openapitools.model; + +import java.net.URI; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import org.springframework.lang.Nullable; +import org.openapitools.jackson.nullable.JsonNullable; +import java.time.OffsetDateTime; +import javax.validation.Valid; +import javax.validation.constraints.*; +import io.swagger.v3.oas.annotations.media.Schema; + + +import java.util.*; +import javax.annotation.Generated; + +/** + * MultipartMixedRequestMarker + */ + +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +public class MultipartMixedRequestMarker { + + private String name; + + private @Nullable Integer priority; + + private @Nullable Boolean active; + + public MultipartMixedRequestMarker() { + super(); + } + + /** + * Constructor with only required parameters + */ + public MultipartMixedRequestMarker(String name) { + this.name = name; + } + + public MultipartMixedRequestMarker name(String name) { + this.name = name; + return this; + } + + /** + * Get name + * @return name + */ + @NotNull + @Schema(name = "name", requiredMode = Schema.RequiredMode.REQUIRED) + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MultipartMixedRequestMarker priority(@Nullable Integer priority) { + this.priority = priority; + return this; + } + + /** + * Get priority + * @return priority + */ + + @Schema(name = "priority", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("priority") + public @Nullable Integer getPriority() { + return priority; + } + + public void setPriority(@Nullable Integer priority) { + this.priority = priority; + } + + public MultipartMixedRequestMarker active(@Nullable Boolean active) { + this.active = active; + return this; + } + + /** + * Get active + * @return active + */ + + @Schema(name = "active", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("active") + public @Nullable Boolean getActive() { + return active; + } + + public void setActive(@Nullable Boolean active) { + this.active = active; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MultipartMixedRequestMarker multipartMixedRequestMarker = (MultipartMixedRequestMarker) o; + return Objects.equals(this.name, multipartMixedRequestMarker.name) && + Objects.equals(this.priority, multipartMixedRequestMarker.priority) && + Objects.equals(this.active, multipartMixedRequestMarker.active); + } + + @Override + public int hashCode() { + return Objects.hash(name, priority, active); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MultipartMixedRequestMarker {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" priority: ").append(toIndentedString(priority)).append("\n"); + sb.append(" active: ").append(toIndentedString(active)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(@Nullable Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/MultipartMixedStatus.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/MultipartMixedStatus.java new file mode 100644 index 000000000000..dfddf2abaaf3 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/model/MultipartMixedStatus.java @@ -0,0 +1,58 @@ +package org.openapitools.model; + +import java.net.URI; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonValue; +import org.openapitools.jackson.nullable.JsonNullable; +import java.time.OffsetDateTime; +import javax.validation.Valid; +import javax.validation.constraints.*; +import io.swagger.v3.oas.annotations.media.Schema; + + +import java.util.*; +import javax.annotation.Generated; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets MultipartMixedStatus + */ + +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +public enum MultipartMixedStatus { + + ALLOWED("ALLOWED"), + + IN_PROGRESS("IN_PROGRESS"), + + REJECTED("REJECTED"); + + private final String value; + + MultipartMixedStatus(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static MultipartMixedStatus fromValue(String value) { + for (MultipartMixedStatus b : MultipartMixedStatus.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/resources/application.properties b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/resources/application.properties new file mode 100644 index 000000000000..7e90813e59b2 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/resources/application.properties @@ -0,0 +1,3 @@ +server.port=8080 +spring.jackson.date-format=org.openapitools.RFC3339DateFormat +spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/resources/openapi.yaml b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/resources/openapi.yaml new file mode 100644 index 000000000000..0fdcb1301243 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/resources/openapi.yaml @@ -0,0 +1,321 @@ +openapi: 3.0.3 +info: + title: Multipart & Byte Edge Case Coverage + version: 1.0.0 +servers: +- url: / +tags: +- name: coverage +paths: + /coverage/query: + get: + operationId: queryParams + parameters: + - explode: true + in: query + name: plain + required: false + schema: + type: string + style: form + - explode: true + in: query + name: bytes + required: false + schema: + format: byte + type: string + style: form + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/path/{plain}/{bytes}: + get: + operationId: pathParams + parameters: + - explode: false + in: path + name: plain + required: true + schema: + type: string + style: simple + - explode: false + in: path + name: bytes + required: true + schema: + format: byte + type: string + style: simple + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/header: + get: + operationId: headerParams + parameters: + - explode: false + in: header + name: X-Plain + required: false + schema: + type: string + style: simple + - explode: false + in: header + name: X-Byte + required: false + schema: + format: byte + type: string + style: simple + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/cookie: + get: + operationId: cookieParams + parameters: + - explode: true + in: cookie + name: plain + required: false + schema: + type: string + style: form + - explode: true + in: cookie + name: bytes + required: false + schema: + format: byte + type: string + style: form + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/form: + post: + operationId: formParams + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: "#/components/schemas/formParams_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/x-www-form-urlencoded + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/simple: + post: + operationId: multipartSimple + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartSimple_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/simple-validated: + post: + operationId: multipartSimpleValidated + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartSimple_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/files: + post: + operationId: multipartFileArray + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartFileArray_request" + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/mixed: + post: + operationId: multipartMixed + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartMixed_request" + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/json: + post: + operationId: jsonBody + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/formParams_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/json + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/binary: + post: + operationId: binaryBody + requestBody: + content: + application/octet-stream: + schema: + format: binary + type: string + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/octet-stream + x-accepts: + - application/json + x-tags: + - tag: coverage +components: + schemas: + MultipartMixedStatus: + enum: + - ALLOWED + - IN_PROGRESS + - REJECTED + type: string + MultipartMixedRequestMarker: + properties: + name: + type: string + priority: + format: int32 + type: integer + active: + type: boolean + required: + - name + type: object + formParams_request: + properties: + plain: + type: string + bytes: + format: byte + type: string + type: object + multipartSimple_request: + properties: + plain: + type: string + bytes: + format: byte + type: string + file: + format: binary + type: string + type: object + multipartFileArray_request: + properties: + files: + items: + format: binary + type: string + type: array + type: object + multipartMixed_request: + properties: + status: + $ref: "#/components/schemas/MultipartMixedStatus" + statusArray: + items: + $ref: "#/components/schemas/MultipartMixedStatus" + type: array + marker: + $ref: "#/components/schemas/MultipartMixedRequestMarker" + markerArray: + items: + $ref: "#/components/schemas/MultipartMixedRequestMarker" + type: array + file: + format: binary + type: string + required: + - file + - status + type: object diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/test/java/org/openapitools/OpenApiGeneratorApplicationTests.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/test/java/org/openapitools/OpenApiGeneratorApplicationTests.java new file mode 100644 index 000000000000..3681f67e7705 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/test/java/org/openapitools/OpenApiGeneratorApplicationTests.java @@ -0,0 +1,13 @@ +package org.openapitools; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class OpenApiGeneratorApplicationTests { + + @Test + void contextLoads() { + } + +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/test/java/org/openapitools/api/CoverageApiIntegrationTest.java b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/test/java/org/openapitools/api/CoverageApiIntegrationTest.java new file mode 100644 index 000000000000..7138207edbf3 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/test/java/org/openapitools/api/CoverageApiIntegrationTest.java @@ -0,0 +1,346 @@ +// manually created counterpart to unit tests. Do not delete! +package org.openapitools.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.openapitools.model.MultipartMixedRequestMarker; +import org.openapitools.model.MultipartMixedStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.MediaType; +import org.springframework.http.client.MultipartBodyBuilder; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.BodyInserters; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; + + +@SpringBootTest +@AutoConfigureWebTestClient +class CoverageApiIntegrationTest { + + @Autowired + private WebTestClient webTestClient; + + @Autowired + private ObjectMapper objectMapper; + + private static final byte[] SAMPLE_BYTES = "hello".getBytes(StandardCharsets.UTF_8); + private static final String SAMPLE_BYTES_BASE64 = Base64.getEncoder().encodeToString(SAMPLE_BYTES); + + // ==================== multipartMixed tests ==================== + // Covers: enum @RequestParam, file @RequestPart, enum array @RequestParam, + // object @RequestPart, object array @RequestPart + + @Test + void multipartMixed_withRequiredFieldsOnly_returns204() throws Exception { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + bodyBuilder.part("file", new ByteArrayResource(SAMPLE_BYTES), MediaType.APPLICATION_OCTET_STREAM); + bodyBuilder.part("status", MultipartMixedStatus.ALLOWED.getValue()); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_MIXED) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void multipartMixed_withAllFields_returns204() throws Exception { + MultipartMixedRequestMarker marker = new MultipartMixedRequestMarker("marker1") + .priority(10) + .active(true); + + List markerArray = Arrays.asList( + new MultipartMixedRequestMarker("marker2").priority(20).active(false), + new MultipartMixedRequestMarker("marker3").priority(30).active(true) + ); + + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + bodyBuilder.part("file", new ByteArrayResource(SAMPLE_BYTES), MediaType.APPLICATION_OCTET_STREAM); + bodyBuilder.part("status", MultipartMixedStatus.IN_PROGRESS.getValue()); + bodyBuilder.part("statusArray", MultipartMixedStatus.ALLOWED.getValue()); + bodyBuilder.part("statusArray", MultipartMixedStatus.REJECTED.getValue()); + bodyBuilder.part("marker", objectMapper.writeValueAsString(marker), MediaType.APPLICATION_JSON); + bodyBuilder.part("markerArray", objectMapper.writeValueAsString(markerArray), MediaType.APPLICATION_JSON); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_MIXED) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void multipartMixed_enumValue_deserializesCorrectly() { + for (MultipartMixedStatus status : MultipartMixedStatus.values()) { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + bodyBuilder.part("file", new ByteArrayResource(SAMPLE_BYTES), MediaType.APPLICATION_OCTET_STREAM); + bodyBuilder.part("status", status.getValue()); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_MIXED) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + } + + // ==================== multipartSimple tests ==================== + // Covers: scalar @RequestParam, base64 bytes @RequestParam, file @RequestPart + + @Test + void multipartSimple_withAllFields_returns204() { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + bodyBuilder.part("file", new ByteArrayResource("content".getBytes()), MediaType.TEXT_PLAIN); + bodyBuilder.part("plain", "plainText"); + bodyBuilder.part("bytes", SAMPLE_BYTES_BASE64); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_SIMPLE) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void multipartSimple_withNoFields_returns204() { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_SIMPLE) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void multipartSimple_withEmptyFilePart_returns204() { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + bodyBuilder.part("file", new ByteArrayResource(new byte[0]), MediaType.APPLICATION_OCTET_STREAM); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_SIMPLE) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== multipartSimpleValidated tests ==================== + // Covers: validated file content deserialization + + @Test + void multipartSimpleValidated_withValidContent_returns204() { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + bodyBuilder.part("file", new ByteArrayResource(SAMPLE_BYTES), MediaType.TEXT_PLAIN); + bodyBuilder.part("plain", "plainText"); + bodyBuilder.part("bytes", SAMPLE_BYTES_BASE64); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_SIMPLE_VALIDATED) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== multipartFileArray tests ==================== + // Covers: array of files @RequestPart List + + @Test + void multipartFileArray_withMultipleFiles_returns204() { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + bodyBuilder.part("files", new ByteArrayResource("content1".getBytes()), MediaType.APPLICATION_OCTET_STREAM) + .filename("file1.bin"); + bodyBuilder.part("files", new ByteArrayResource("content2".getBytes()), MediaType.APPLICATION_OCTET_STREAM) + .filename("file2.bin"); + bodyBuilder.part("files", new ByteArrayResource("content3".getBytes()), MediaType.APPLICATION_OCTET_STREAM) + .filename("file3.bin"); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_FILE_ARRAY) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void multipartFileArray_withNoFiles_returns204() { + MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder(); + + webTestClient + .post() + .uri(CoverageApi.PATH_MULTIPART_FILE_ARRAY) + .body(BodyInserters.fromMultipartData(bodyBuilder.build())) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== formParams tests ==================== + // Covers: application/x-www-form-urlencoded with @RequestParam + + @Test + void formParams_withAllFields_returns204() { + webTestClient + .post() + .uri(CoverageApi.PATH_FORM_PARAMS) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .bodyValue("plain=plainValue&bytes=" + SAMPLE_BYTES_BASE64) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void formParams_withNoFields_returns204() { + webTestClient + .post() + .uri(CoverageApi.PATH_FORM_PARAMS) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== queryParams tests ==================== + // Covers: query string @RequestParam + + @Test + void queryParams_withAllParams_returns204() { + webTestClient + .get() + .uri(uriBuilder -> uriBuilder + .path(CoverageApi.PATH_QUERY_PARAMS) + .queryParam("plain", "queryPlain") + .queryParam("bytes", SAMPLE_BYTES_BASE64) + .build()) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void queryParams_withNoParams_returns204() { + webTestClient + .get() + .uri(CoverageApi.PATH_QUERY_PARAMS) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== pathParams tests ==================== + // Covers: @PathVariable + + @Test + void pathParams_withBothParams_returns204() { + webTestClient + .get() + .uri("/coverage/path/{plain}/{bytes}", "pathPlain", SAMPLE_BYTES_BASE64) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== headerParams tests ==================== + // Covers: @RequestHeader + + @Test + void headerParams_withAllHeaders_returns204() { + webTestClient + .get() + .uri(CoverageApi.PATH_HEADER_PARAMS) + .header("X-Plain", "headerPlain") + .header("X-Byte", SAMPLE_BYTES_BASE64) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void headerParams_withNoHeaders_returns204() { + webTestClient + .get() + .uri(CoverageApi.PATH_HEADER_PARAMS) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== cookieParams tests ==================== + // Covers: @CookieValue + + @Test + void cookieParams_withAllCookies_returns204() { + webTestClient + .get() + .uri(CoverageApi.PATH_COOKIE_PARAMS) + .cookie("plain", "cookiePlain") + .cookie("bytes", SAMPLE_BYTES_BASE64) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void cookieParams_withNoCookies_returns204() { + webTestClient + .get() + .uri(CoverageApi.PATH_COOKIE_PARAMS) + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== jsonBody tests ==================== + // Covers: @RequestBody with JSON POJO + + @Test + void jsonBody_withValidBody_returns204() { + String json = "{\"plain\": \"jsonPlain\", \"bytes\": \"" + SAMPLE_BYTES_BASE64 + "\"}"; + + webTestClient + .post() + .uri(CoverageApi.PATH_JSON_BODY) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(json) + .exchange() + .expectStatus().isNoContent(); + } + + @Test + void jsonBody_withEmptyObject_returns204() { + webTestClient + .post() + .uri(CoverageApi.PATH_JSON_BODY) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue("{}") + .exchange() + .expectStatus().isNoContent(); + } + + // ==================== binaryBody tests ==================== + // Covers: @RequestBody with application/octet-stream Resource + + @Test + void binaryBody_withBinaryContent_returns204() { + webTestClient + .post() + .uri(CoverageApi.PATH_BINARY_BODY) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .bodyValue(SAMPLE_BYTES) + .exchange() + .expectStatus().isNoContent(); + } + +} diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator-ignore b/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator/FILES b/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator/FILES new file mode 100644 index 000000000000..7e2ea15534aa --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator/FILES @@ -0,0 +1,8 @@ +README.md +pom.xml +src/main/java/org/openapitools/api/ApiUtil.java +src/main/java/org/openapitools/api/CoverageApi.java +src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java +src/main/java/org/openapitools/model/FormParamsRequest.java +src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java +src/main/java/org/openapitools/model/MultipartMixedStatus.java diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator/VERSION b/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/README.md b/samples/server/petstore/springboot-byte-format-edge-cases/README.md new file mode 100644 index 000000000000..d43a1de307df --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/README.md @@ -0,0 +1,27 @@ + +# OpenAPI generated API stub + +Spring Framework stub + + +## Overview +This code was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. +By using the [OpenAPI-Spec](https://openapis.org), you can easily generate an API stub. +This is an example of building API stub interfaces in Java using the Spring framework. + +The stubs generated can be used in your existing Spring-MVC or Spring-Boot application to create controller endpoints +by adding ```@Controller``` classes that implement the interface. Eg: +```java +@Controller +public class PetController implements PetApi { +// implement all PetApi methods +} +``` + +You can also use the interface to create [Spring-Cloud Feign clients](http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign-inheritance).Eg: +```java +@FeignClient(name="pet", url="http://petstore.swagger.io/v2") +public interface PetClient extends PetApi { + +} +``` diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/pom.xml b/samples/server/petstore/springboot-byte-format-edge-cases/pom.xml new file mode 100644 index 000000000000..37aba04fbe66 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/pom.xml @@ -0,0 +1,88 @@ + + 4.0.0 + org.openapitools + springboot + jar + springboot + 1.0.0-SNAPSHOT + + 1.8 + ${java.version} + ${java.version} + UTF-8 + 1.6.14 + 5.3.1 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.15 + + + + src/main/java + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.data + spring-data-commons + + + + org.springdoc + springdoc-openapi-ui + ${springdoc.version} + + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + org.openapitools + jackson-databind-nullable + 0.2.8 + + + + org.springframework.boot + spring-boot-starter-validation + + + com.fasterxml.jackson.core + jackson-databind + + + org.springframework.boot + spring-boot-starter-test + test + + + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/OpenApiGeneratorApplication.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/OpenApiGeneratorApplication.java new file mode 100644 index 000000000000..97252a8a9402 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/OpenApiGeneratorApplication.java @@ -0,0 +1,30 @@ +package org.openapitools; + +import com.fasterxml.jackson.databind.Module; +import org.openapitools.jackson.nullable.JsonNullableModule; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator; + +@SpringBootApplication( + nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class +) +@ComponentScan( + basePackages = {"org.openapitools", "org.openapitools.api" , "org.openapitools.configuration"}, + nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class +) +public class OpenApiGeneratorApplication { + + public static void main(String[] args) { + SpringApplication.run(OpenApiGeneratorApplication.class, args); + } + + @Bean(name = "org.openapitools.OpenApiGeneratorApplication.jsonNullableModule") + public Module jsonNullableModule() { + return new JsonNullableModule(); + } + +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java new file mode 100644 index 000000000000..bcd3936d8b34 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java @@ -0,0 +1,38 @@ +package org.openapitools; + +import com.fasterxml.jackson.databind.util.StdDateFormat; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +public class RFC3339DateFormat extends DateFormat { + private static final long serialVersionUID = 1L; + private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); + + private final StdDateFormat fmt = new StdDateFormat() + .withTimeZone(TIMEZONE_Z) + .withColonInTimeZone(true); + + public RFC3339DateFormat() { + this.calendar = new GregorianCalendar(); + } + + @Override + public Date parse(String source, ParsePosition pos) { + return fmt.parse(source, pos); + } + + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + return fmt.format(date, toAppendTo, fieldPosition); + } + + @Override + public Object clone() { + return this; + } +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/ApiUtil.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/ApiUtil.java new file mode 100644 index 000000000000..c03486e4081d --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/ApiUtil.java @@ -0,0 +1,21 @@ +package org.openapitools.api; + +import org.springframework.web.context.request.NativeWebRequest; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class ApiUtil { + public static void setExampleResponse(NativeWebRequest req, String contentType, String example) { + try { + HttpServletResponse res = req.getNativeResponse(HttpServletResponse.class); + if (res != null) { + res.setCharacterEncoding("UTF-8"); + res.addHeader("Content-Type", contentType); + res.getWriter().print(example); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApi.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApi.java new file mode 100644 index 000000000000..f173d0b7340d --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApi.java @@ -0,0 +1,366 @@ +/* + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (7.20.0-SNAPSHOT). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package org.openapitools.api; + +import org.openapitools.model.FormParamsRequest; +import org.openapitools.model.MultipartMixedRequestMarker; +import org.openapitools.model.MultipartMixedStatus; +import org.springframework.lang.Nullable; +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import javax.annotation.Generated; + +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +@Validated +@Tag(name = "coverage", description = "the coverage API") +public interface CoverageApi { + + default Optional getRequest() { + return Optional.empty(); + } + + String PATH_BINARY_BODY = "/coverage/binary"; + /** + * POST /coverage/binary + * + * @param body (required) + * @return No content (status code 204) + */ + @Operation( + operationId = "binaryBody", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_BINARY_BODY, + consumes = { "application/octet-stream" } + ) + default ResponseEntity binaryBody( + @Parameter(name = "body", description = "", required = true) @Valid @RequestBody org.springframework.core.io.Resource body + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_COOKIE_PARAMS = "/coverage/cookie"; + /** + * GET /coverage/cookie + * + * @param plain (optional) + * @param bytes (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "cookieParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_COOKIE_PARAMS + ) + default ResponseEntity cookieParams( + @Parameter(name = "plain", description = "", in = ParameterIn.COOKIE) @CookieValue(name = "plain", required = false) @Nullable String plain, + @Parameter(name = "bytes", description = "", in = ParameterIn.COOKIE) @CookieValue(name = "bytes", required = false) @Nullable String bytes /* base64 encoded binary */ + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_FORM_PARAMS = "/coverage/form"; + /** + * POST /coverage/form + * + * @param plain (optional) + * @param bytes (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "formParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_FORM_PARAMS, + consumes = { "application/x-www-form-urlencoded" } + ) + default ResponseEntity formParams( + @Parameter(name = "plain", description = "") @Valid @RequestParam(value = "plain", required = false) String plain, + @Parameter(name = "bytes", description = "") @Valid @RequestParam(value = "bytes", required = false) String bytes /* base64 encoded binary */ + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_HEADER_PARAMS = "/coverage/header"; + /** + * GET /coverage/header + * + * @param xPlain (optional) + * @param xByte (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "headerParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_HEADER_PARAMS + ) + default ResponseEntity headerParams( + @Parameter(name = "X-Plain", description = "", in = ParameterIn.HEADER) @RequestHeader(value = "X-Plain", required = false) @Nullable String xPlain, + @Parameter(name = "X-Byte", description = "", in = ParameterIn.HEADER) @RequestHeader(value = "X-Byte", required = false) @Nullable String xByte /* base64 encoded binary */ + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_JSON_BODY = "/coverage/json"; + /** + * POST /coverage/json + * + * @param formParamsRequest (required) + * @return No content (status code 204) + */ + @Operation( + operationId = "jsonBody", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_JSON_BODY, + consumes = { "application/json" } + ) + default ResponseEntity jsonBody( + @Parameter(name = "FormParamsRequest", description = "", required = true) @Valid @RequestBody FormParamsRequest formParamsRequest + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_MULTIPART_FILE_ARRAY = "/coverage/multipart/files"; + /** + * POST /coverage/multipart/files + * + * @param files (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartFileArray", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_FILE_ARRAY, + consumes = { "multipart/form-data" } + ) + default ResponseEntity multipartFileArray( + @Parameter(name = "files", description = "") @RequestPart(value = "files", required = false) List files + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_MULTIPART_MIXED = "/coverage/multipart/mixed"; + /** + * POST /coverage/multipart/mixed + * + * @param status (required) + * @param file (required) + * @param statusArray (optional) + * @param marker (optional) + * @param markerArray (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartMixed", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_MIXED, + consumes = { "multipart/form-data" } + ) + default ResponseEntity multipartMixed( + @Parameter(name = "status", description = "", required = true) @Valid @RequestParam(value = "status", required = true) MultipartMixedStatus status, + @Parameter(name = "file", description = "", required = true) @RequestPart(value = "file", required = true) MultipartFile file, + @Parameter(name = "statusArray", description = "") @Valid @RequestParam(value = "statusArray", required = false) List statusArray, + @Parameter(name = "marker", description = "") @Valid @RequestPart(value = "marker", required = false) MultipartMixedRequestMarker marker, + @Parameter(name = "markerArray", description = "") @Valid @RequestPart(value = "markerArray", required = false) List<@Valid MultipartMixedRequestMarker> markerArray + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_MULTIPART_SIMPLE = "/coverage/multipart/simple"; + /** + * POST /coverage/multipart/simple + * + * @param plain (optional) + * @param bytes (optional) + * @param file (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartSimple", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_SIMPLE, + consumes = { "multipart/form-data" } + ) + default ResponseEntity multipartSimple( + @Parameter(name = "plain", description = "") @Valid @RequestParam(value = "plain", required = false) String plain, + @Parameter(name = "bytes", description = "") @Valid @RequestParam(value = "bytes", required = false) String bytes /* base64 encoded binary */, + @Parameter(name = "file", description = "") @RequestPart(value = "file", required = false) MultipartFile file + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_MULTIPART_SIMPLE_VALIDATED = "/coverage/multipart/simple-validated"; + /** + * POST /coverage/multipart/simple-validated + * + * @param plain (optional) + * @param bytes (optional) + * @param file (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "multipartSimpleValidated", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.POST, + value = CoverageApi.PATH_MULTIPART_SIMPLE_VALIDATED, + consumes = { "multipart/form-data" } + ) + default ResponseEntity multipartSimpleValidated( + @Parameter(name = "plain", description = "") @Valid @RequestParam(value = "plain", required = false) String plain, + @Parameter(name = "bytes", description = "") @Valid @RequestParam(value = "bytes", required = false) String bytes /* base64 encoded binary */, + @Parameter(name = "file", description = "") @RequestPart(value = "file", required = false) MultipartFile file + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_PATH_PARAMS = "/coverage/path/{plain}/{bytes}"; + /** + * GET /coverage/path/{plain}/{bytes} + * + * @param plain (required) + * @param bytes (required) + * @return No content (status code 204) + */ + @Operation( + operationId = "pathParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_PATH_PARAMS + ) + default ResponseEntity pathParams( + @NotNull @Parameter(name = "plain", description = "", required = true, in = ParameterIn.PATH) @PathVariable("plain") String plain, + @NotNull @Parameter(name = "bytes", description = "", required = true, in = ParameterIn.PATH) @PathVariable("bytes") String bytes /* base64 encoded binary */ + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + String PATH_QUERY_PARAMS = "/coverage/query"; + /** + * GET /coverage/query + * + * @param plain (optional) + * @param bytes (optional) + * @return No content (status code 204) + */ + @Operation( + operationId = "queryParams", + tags = { "coverage" }, + responses = { + @ApiResponse(responseCode = "204", description = "No content") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = CoverageApi.PATH_QUERY_PARAMS + ) + default ResponseEntity queryParams( + @Parameter(name = "plain", description = "", in = ParameterIn.QUERY) @Valid @RequestParam(value = "plain", required = false) @Nullable String plain, + @Parameter(name = "bytes", description = "", in = ParameterIn.QUERY) @Valid @RequestParam(value = "bytes", required = false) @Nullable String bytes /* base64 encoded binary */ + ) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + +} diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java new file mode 100644 index 000000000000..f85e6755dfe9 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java @@ -0,0 +1,248 @@ +// manually created counterpart to unit tests. Do not delete! +package org.openapitools.api; + +import org.openapitools.model.FormParamsRequest; +import org.openapitools.model.MultipartMixedRequestMarker; +import org.openapitools.model.MultipartMixedStatus; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.multipart.MultipartFile; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; + +@Controller +@RequestMapping("${openapi.multipartByteEdgeCaseCoverage.base-path:}") +public class CoverageApiTestControllerImpl implements CoverageApi { + + // Expected content for binary data verification - matches test constants + private static final byte[] EXPECTED_BYTES = "hello".getBytes(StandardCharsets.UTF_8); + private static final String EXPECTED_BYTES_STRING = "hello"; + + private void verifyBytesContent(byte[] actual, String fieldName) { + if (!Arrays.equals(EXPECTED_BYTES, actual)) { + String actualString = new String(actual, StandardCharsets.UTF_8); + throw new IllegalArgumentException( + fieldName + " content mismatch: expected '" + EXPECTED_BYTES_STRING + "', got '" + actualString + "'"); + } + } + + private void verifyBase64Content(String base64Value, String fieldName) { + byte[] decoded = Base64.getDecoder().decode(base64Value); + verifyBytesContent(decoded, fieldName); + } + + @Override + public ResponseEntity binaryBody(Resource body) { + if (body == null) { + throw new IllegalArgumentException("body is required"); + } + try { + byte[] content = readAllBytes(body.getInputStream()); + if (content.length == 0) { + throw new IllegalArgumentException("body content is empty"); + } + verifyBytesContent(content, "body"); + } catch (IOException e) { + throw new RuntimeException("Failed to read binary body", e); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + private byte[] readAllBytes(InputStream inputStream) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[1024]; + while ((nRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + return buffer.toByteArray(); + } + + @Override + public ResponseEntity cookieParams(String plain, String bytes) { + if (bytes != null) { + verifyBase64Content(bytes, "bytes"); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity formParams(String plain, String bytes) { + if (bytes != null) { + verifyBase64Content(bytes, "bytes"); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity headerParams(String xPlain, String xByte) { + if (xByte != null) { + verifyBase64Content(xByte, "X-Byte"); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity jsonBody(FormParamsRequest formParamsRequest) { + if (formParamsRequest == null) { + throw new IllegalArgumentException("formParamsRequest is required"); + } + byte[] bytes = formParamsRequest.getBytes(); + if (bytes != null) { + verifyBytesContent(bytes, "bytes"); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity multipartFileArray(List files) { + // Expected content for each file in the array - matches test constants + String[] expectedContents = {"content1", "content2", "content3"}; + + if (files != null) { + for (int i = 0; i < files.size(); i++) { + MultipartFile file = files.get(i); + try { + byte[] content = file.getBytes(); + if (content.length == 0) { + throw new IllegalArgumentException("files[" + i + "] content is empty"); + } + // Verify content matches expected value for this index + if (i < expectedContents.length) { + byte[] expected = expectedContents[i].getBytes(StandardCharsets.UTF_8); + if (!Arrays.equals(expected, content)) { + String actualString = new String(content, StandardCharsets.UTF_8); + throw new IllegalArgumentException( + "files[" + i + "] content mismatch: expected '" + expectedContents[i] + "', got '" + actualString + "'"); + } + } + } catch (IOException e) { + throw new RuntimeException("Failed to read file", e); + } + } + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity multipartMixed( + MultipartMixedStatus status, + MultipartFile file, + List statusArray, + MultipartMixedRequestMarker marker, + List markerArray + ) { + if (status == null) { + throw new IllegalArgumentException("status is required"); + } + if (file == null) { + throw new IllegalArgumentException("file is required"); + } + + // Verify enum value is valid + String reconstructedStatus = status.getValue(); + if (reconstructedStatus == null || reconstructedStatus.isEmpty()) { + throw new IllegalArgumentException("status value is invalid"); + } + + // Verify file content matches expected bytes + try { + byte[] fileContent = file.getBytes(); + verifyBytesContent(fileContent, "file"); + } catch (IOException e) { + throw new RuntimeException("Failed to read file", e); + } + + // Verify enum array values + if (statusArray != null) { + for (int i = 0; i < statusArray.size(); i++) { + MultipartMixedStatus s = statusArray.get(i); + String value = s.getValue(); + if (value == null) { + throw new IllegalArgumentException("statusArray[" + i + "] contains invalid enum"); + } + } + } + + // Verify POJO fields + if (marker != null) { + String name = marker.getName(); + if (name == null) { + throw new IllegalArgumentException("marker.name is required"); + } + } + + // Verify POJO array fields + if (markerArray != null) { + for (int i = 0; i < markerArray.size(); i++) { + MultipartMixedRequestMarker m = markerArray.get(i); + String name = m.getName(); + if (name == null) { + throw new IllegalArgumentException("markerArray[" + i + "].name is required"); + } + } + } + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity multipartSimple(String plain, String bytes, MultipartFile file) { + // This endpoint does NOT validate file content - allows empty files + if (bytes != null) { + verifyBase64Content(bytes, "bytes"); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity multipartSimpleValidated(String plain, String bytes, MultipartFile file) { + // This endpoint validates file content + if (bytes != null) { + verifyBase64Content(bytes, "bytes"); + } + if (file != null) { + try { + byte[] content = file.getBytes(); + if (content.length == 0) { + throw new IllegalArgumentException("file content is empty"); + } + verifyBytesContent(content, "file"); + } catch (IOException e) { + throw new RuntimeException("Failed to read file", e); + } + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity pathParams(String plain, String bytes) { + if (plain == null) { + throw new IllegalArgumentException("plain is required"); + } + if (bytes == null) { + throw new IllegalArgumentException("bytes is required"); + } + verifyBase64Content(bytes, "bytes"); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity queryParams(String plain, String bytes) { + if (bytes != null) { + verifyBase64Content(bytes, "bytes"); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java new file mode 100644 index 000000000000..7c174fb2fd4d --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/EnumConverterConfiguration.java @@ -0,0 +1,29 @@ +package org.openapitools.configuration; + +import org.openapitools.model.MultipartMixedStatus; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; + +/** + * This class provides Spring Converter beans for the enum models in the OpenAPI specification. + * + * By default, Spring only converts primitive types to enums using Enum::valueOf, which can prevent + * correct conversion if the OpenAPI specification is using an `enumPropertyNaming` other than + * `original` or the specification has an integer enum. + */ +@Configuration(value = "org.openapitools.configuration.enumConverterConfiguration") +public class EnumConverterConfiguration { + + @Bean(name = "org.openapitools.configuration.EnumConverterConfiguration.multipartMixedStatusConverter") + Converter multipartMixedStatusConverter() { + return new Converter() { + @Override + public MultipartMixedStatus convert(String source) { + return MultipartMixedStatus.fromValue(source); + } + }; + } + +} diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/HomeController.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/HomeController.java new file mode 100644 index 000000000000..9aa29284ab5f --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/HomeController.java @@ -0,0 +1,20 @@ +package org.openapitools.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * Home redirection to OpenAPI api documentation + */ +@Controller +public class HomeController { + + @RequestMapping("/") + public String index() { + return "redirect:swagger-ui.html"; + } + +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/SpringDocConfiguration.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/SpringDocConfiguration.java new file mode 100644 index 000000000000..656402210dcd --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/SpringDocConfiguration.java @@ -0,0 +1,27 @@ +package org.openapitools.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.security.SecurityScheme; + +@Configuration +public class SpringDocConfiguration { + + @Bean(name = "org.openapitools.configuration.SpringDocConfiguration.apiInfo") + OpenAPI apiInfo() { + return new OpenAPI() + .info( + new Info() + .title("Multipart & Byte Edge Case Coverage") + .description("No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)") + .version("1.0.0") + ) + ; + } +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/FormParamsRequest.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/FormParamsRequest.java new file mode 100644 index 000000000000..45a6712a7e0f --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/FormParamsRequest.java @@ -0,0 +1,111 @@ +package org.openapitools.model; + +import java.net.URI; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import java.util.Arrays; +import org.springframework.lang.Nullable; +import org.openapitools.jackson.nullable.JsonNullable; +import java.time.OffsetDateTime; +import javax.validation.Valid; +import javax.validation.constraints.*; +import io.swagger.v3.oas.annotations.media.Schema; + + +import java.util.*; +import javax.annotation.Generated; + +/** + * FormParamsRequest + */ + +@JsonTypeName("formParams_request") +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +public class FormParamsRequest { + + private @Nullable String plain; + + private @Nullable byte[] bytes; + + public FormParamsRequest plain(@Nullable String plain) { + this.plain = plain; + return this; + } + + /** + * Get plain + * @return plain + */ + + @Schema(name = "plain", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("plain") + public @Nullable String getPlain() { + return plain; + } + + public void setPlain(@Nullable String plain) { + this.plain = plain; + } + + public FormParamsRequest bytes(@Nullable byte[] bytes) { + this.bytes = bytes; + return this; + } + + /** + * Get bytes + * @return bytes + */ + + @Schema(name = "bytes", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("bytes") + public @Nullable byte[] getBytes() { + return bytes; + } + + public void setBytes(@Nullable byte[] bytes) { + this.bytes = bytes; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FormParamsRequest formParamsRequest = (FormParamsRequest) o; + return Objects.equals(this.plain, formParamsRequest.plain) && + Arrays.equals(this.bytes, formParamsRequest.bytes); + } + + @Override + public int hashCode() { + return Objects.hash(plain, Arrays.hashCode(bytes)); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class FormParamsRequest {\n"); + sb.append(" plain: ").append(toIndentedString(plain)).append("\n"); + sb.append(" bytes: ").append(toIndentedString(bytes)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(@Nullable Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java new file mode 100644 index 000000000000..6f25fa78d166 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/MultipartMixedRequestMarker.java @@ -0,0 +1,143 @@ +package org.openapitools.model; + +import java.net.URI; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import org.springframework.lang.Nullable; +import org.openapitools.jackson.nullable.JsonNullable; +import java.time.OffsetDateTime; +import javax.validation.Valid; +import javax.validation.constraints.*; +import io.swagger.v3.oas.annotations.media.Schema; + + +import java.util.*; +import javax.annotation.Generated; + +/** + * MultipartMixedRequestMarker + */ + +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +public class MultipartMixedRequestMarker { + + private String name; + + private @Nullable Integer priority; + + private @Nullable Boolean active; + + public MultipartMixedRequestMarker() { + super(); + } + + /** + * Constructor with only required parameters + */ + public MultipartMixedRequestMarker(String name) { + this.name = name; + } + + public MultipartMixedRequestMarker name(String name) { + this.name = name; + return this; + } + + /** + * Get name + * @return name + */ + @NotNull + @Schema(name = "name", requiredMode = Schema.RequiredMode.REQUIRED) + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MultipartMixedRequestMarker priority(@Nullable Integer priority) { + this.priority = priority; + return this; + } + + /** + * Get priority + * @return priority + */ + + @Schema(name = "priority", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("priority") + public @Nullable Integer getPriority() { + return priority; + } + + public void setPriority(@Nullable Integer priority) { + this.priority = priority; + } + + public MultipartMixedRequestMarker active(@Nullable Boolean active) { + this.active = active; + return this; + } + + /** + * Get active + * @return active + */ + + @Schema(name = "active", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("active") + public @Nullable Boolean getActive() { + return active; + } + + public void setActive(@Nullable Boolean active) { + this.active = active; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MultipartMixedRequestMarker multipartMixedRequestMarker = (MultipartMixedRequestMarker) o; + return Objects.equals(this.name, multipartMixedRequestMarker.name) && + Objects.equals(this.priority, multipartMixedRequestMarker.priority) && + Objects.equals(this.active, multipartMixedRequestMarker.active); + } + + @Override + public int hashCode() { + return Objects.hash(name, priority, active); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MultipartMixedRequestMarker {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" priority: ").append(toIndentedString(priority)).append("\n"); + sb.append(" active: ").append(toIndentedString(active)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(@Nullable Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/MultipartMixedStatus.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/MultipartMixedStatus.java new file mode 100644 index 000000000000..dfddf2abaaf3 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/model/MultipartMixedStatus.java @@ -0,0 +1,58 @@ +package org.openapitools.model; + +import java.net.URI; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonValue; +import org.openapitools.jackson.nullable.JsonNullable; +import java.time.OffsetDateTime; +import javax.validation.Valid; +import javax.validation.constraints.*; +import io.swagger.v3.oas.annotations.media.Schema; + + +import java.util.*; +import javax.annotation.Generated; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets MultipartMixedStatus + */ + +@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.20.0-SNAPSHOT") +public enum MultipartMixedStatus { + + ALLOWED("ALLOWED"), + + IN_PROGRESS("IN_PROGRESS"), + + REJECTED("REJECTED"); + + private final String value; + + MultipartMixedStatus(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static MultipartMixedStatus fromValue(String value) { + for (MultipartMixedStatus b : MultipartMixedStatus.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/resources/application.properties b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/resources/application.properties new file mode 100644 index 000000000000..7e90813e59b2 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/resources/application.properties @@ -0,0 +1,3 @@ +server.port=8080 +spring.jackson.date-format=org.openapitools.RFC3339DateFormat +spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/main/resources/openapi.yaml b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/resources/openapi.yaml new file mode 100644 index 000000000000..0fdcb1301243 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/main/resources/openapi.yaml @@ -0,0 +1,321 @@ +openapi: 3.0.3 +info: + title: Multipart & Byte Edge Case Coverage + version: 1.0.0 +servers: +- url: / +tags: +- name: coverage +paths: + /coverage/query: + get: + operationId: queryParams + parameters: + - explode: true + in: query + name: plain + required: false + schema: + type: string + style: form + - explode: true + in: query + name: bytes + required: false + schema: + format: byte + type: string + style: form + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/path/{plain}/{bytes}: + get: + operationId: pathParams + parameters: + - explode: false + in: path + name: plain + required: true + schema: + type: string + style: simple + - explode: false + in: path + name: bytes + required: true + schema: + format: byte + type: string + style: simple + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/header: + get: + operationId: headerParams + parameters: + - explode: false + in: header + name: X-Plain + required: false + schema: + type: string + style: simple + - explode: false + in: header + name: X-Byte + required: false + schema: + format: byte + type: string + style: simple + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/cookie: + get: + operationId: cookieParams + parameters: + - explode: true + in: cookie + name: plain + required: false + schema: + type: string + style: form + - explode: true + in: cookie + name: bytes + required: false + schema: + format: byte + type: string + style: form + responses: + "204": + description: No content + tags: + - coverage + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/form: + post: + operationId: formParams + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: "#/components/schemas/formParams_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/x-www-form-urlencoded + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/simple: + post: + operationId: multipartSimple + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartSimple_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/simple-validated: + post: + operationId: multipartSimpleValidated + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartSimple_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/files: + post: + operationId: multipartFileArray + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartFileArray_request" + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/multipart/mixed: + post: + operationId: multipartMixed + requestBody: + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/multipartMixed_request" + responses: + "204": + description: No content + tags: + - coverage + x-content-type: multipart/form-data + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/json: + post: + operationId: jsonBody + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/formParams_request" + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/json + x-accepts: + - application/json + x-tags: + - tag: coverage + /coverage/binary: + post: + operationId: binaryBody + requestBody: + content: + application/octet-stream: + schema: + format: binary + type: string + required: true + responses: + "204": + description: No content + tags: + - coverage + x-content-type: application/octet-stream + x-accepts: + - application/json + x-tags: + - tag: coverage +components: + schemas: + MultipartMixedStatus: + enum: + - ALLOWED + - IN_PROGRESS + - REJECTED + type: string + MultipartMixedRequestMarker: + properties: + name: + type: string + priority: + format: int32 + type: integer + active: + type: boolean + required: + - name + type: object + formParams_request: + properties: + plain: + type: string + bytes: + format: byte + type: string + type: object + multipartSimple_request: + properties: + plain: + type: string + bytes: + format: byte + type: string + file: + format: binary + type: string + type: object + multipartFileArray_request: + properties: + files: + items: + format: binary + type: string + type: array + type: object + multipartMixed_request: + properties: + status: + $ref: "#/components/schemas/MultipartMixedStatus" + statusArray: + items: + $ref: "#/components/schemas/MultipartMixedStatus" + type: array + marker: + $ref: "#/components/schemas/MultipartMixedRequestMarker" + markerArray: + items: + $ref: "#/components/schemas/MultipartMixedRequestMarker" + type: array + file: + format: binary + type: string + required: + - file + - status + type: object diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/test/java/org/openapitools/OpenApiGeneratorApplicationTests.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/test/java/org/openapitools/OpenApiGeneratorApplicationTests.java new file mode 100644 index 000000000000..3681f67e7705 --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/test/java/org/openapitools/OpenApiGeneratorApplicationTests.java @@ -0,0 +1,13 @@ +package org.openapitools; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class OpenApiGeneratorApplicationTests { + + @Test + void contextLoads() { + } + +} \ No newline at end of file diff --git a/samples/server/petstore/springboot-byte-format-edge-cases/src/test/java/org/openapitools/api/CoverageApiIntegrationTest.java b/samples/server/petstore/springboot-byte-format-edge-cases/src/test/java/org/openapitools/api/CoverageApiIntegrationTest.java new file mode 100644 index 000000000000..cd3c06d2e82b --- /dev/null +++ b/samples/server/petstore/springboot-byte-format-edge-cases/src/test/java/org/openapitools/api/CoverageApiIntegrationTest.java @@ -0,0 +1,275 @@ +// manually created counterpart to unit tests. Do not delete! +package org.openapitools.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.openapitools.model.MultipartMixedRequestMarker; +import org.openapitools.model.MultipartMixedStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; + +import javax.servlet.http.Cookie; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +@SpringBootTest +@AutoConfigureMockMvc +class CoverageApiIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + private static final byte[] SAMPLE_BYTES = "hello".getBytes(StandardCharsets.UTF_8); + private static final String SAMPLE_BYTES_BASE64 = Base64.getEncoder().encodeToString(SAMPLE_BYTES); + + // ==================== multipartMixed tests ==================== + // Covers: enum @RequestParam, file @RequestPart, enum array @RequestParam, + // object @RequestPart, object array @RequestPart + + @Test + void multipartMixed_withRequiredFieldsOnly_returns204() throws Exception { + MockMultipartFile file = new MockMultipartFile( + "file", "test.bin", MediaType.APPLICATION_OCTET_STREAM_VALUE, SAMPLE_BYTES); + + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_MIXED) + .file(file) + .param("status", MultipartMixedStatus.ALLOWED.getValue())) + .andExpect(status().isNoContent()); + } + + @Test + void multipartMixed_withAllFields_returns204() throws Exception { + MockMultipartFile file = new MockMultipartFile( + "file", "test.bin", MediaType.APPLICATION_OCTET_STREAM_VALUE, SAMPLE_BYTES); + + MultipartMixedRequestMarker marker = new MultipartMixedRequestMarker("marker1") + .priority(10) + .active(true); + + List markerArray = Arrays.asList( + new MultipartMixedRequestMarker("marker2").priority(20).active(false), + new MultipartMixedRequestMarker("marker3").priority(30).active(true) + ); + + // marker as JSON part + MockMultipartFile markerPart = new MockMultipartFile( + "marker", "", MediaType.APPLICATION_JSON_VALUE, + objectMapper.writeValueAsBytes(marker)); + + // markerArray as JSON part + MockMultipartFile markerArrayPart = new MockMultipartFile( + "markerArray", "", MediaType.APPLICATION_JSON_VALUE, + objectMapper.writeValueAsBytes(markerArray)); + + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_MIXED) + .file(file) + .file(markerPart) + .file(markerArrayPart) + .param("status", MultipartMixedStatus.IN_PROGRESS.getValue()) + .param("statusArray", MultipartMixedStatus.ALLOWED.getValue(), + MultipartMixedStatus.REJECTED.getValue())) + .andExpect(status().isNoContent()); + } + + @Test + void multipartMixed_enumValue_deserializesCorrectly() throws Exception { + MockMultipartFile file = new MockMultipartFile( + "file", "test.bin", MediaType.APPLICATION_OCTET_STREAM_VALUE, SAMPLE_BYTES); + + // Test each enum value + for (MultipartMixedStatus status : MultipartMixedStatus.values()) { + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_MIXED) + .file(file) + .param("status", status.getValue())) + .andExpect(status().isNoContent()); + } + } + + // ==================== multipartSimple tests ==================== + // Covers: scalar @RequestParam, base64 bytes @RequestParam, file @RequestPart + + @Test + void multipartSimple_withAllFields_returns204() throws Exception { + MockMultipartFile file = new MockMultipartFile( + "file", "test.txt", MediaType.TEXT_PLAIN_VALUE, SAMPLE_BYTES); + + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_SIMPLE) + .file(file) + .param("plain", "plainText") + .param("bytes", SAMPLE_BYTES_BASE64)) + .andExpect(status().isNoContent()); + } + + @Test + void multipartSimple_withEmptyFilePart_returns204() throws Exception { + MockMultipartFile emptyFile = + new MockMultipartFile("file", "", MediaType.APPLICATION_OCTET_STREAM_VALUE, new byte[0]); + + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_SIMPLE) + .file(emptyFile)) + .andExpect(status().isNoContent()); + } + + // ==================== multipartSimpleValidated tests ==================== + // Covers: validated file content deserialization + + @Test + void multipartSimpleValidated_withValidContent_returns204() throws Exception { + MockMultipartFile file = new MockMultipartFile( + "file", "test.txt", MediaType.TEXT_PLAIN_VALUE, SAMPLE_BYTES); + + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_SIMPLE_VALIDATED) + .file(file) + .param("plain", "plainText") + .param("bytes", SAMPLE_BYTES_BASE64)) + .andExpect(status().isNoContent()); + } + + // ==================== multipartFileArray tests ==================== + // Covers: array of files @RequestPart List + + @Test + void multipartFileArray_withMultipleFiles_returns204() throws Exception { + MockMultipartFile file1 = new MockMultipartFile( + "files", "file1.bin", MediaType.APPLICATION_OCTET_STREAM_VALUE, "content1".getBytes()); + MockMultipartFile file2 = new MockMultipartFile( + "files", "file2.bin", MediaType.APPLICATION_OCTET_STREAM_VALUE, "content2".getBytes()); + MockMultipartFile file3 = new MockMultipartFile( + "files", "file3.bin", MediaType.APPLICATION_OCTET_STREAM_VALUE, "content3".getBytes()); + + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_FILE_ARRAY) + .file(file1) + .file(file2) + .file(file3)) + .andExpect(status().isNoContent()); + } + + @Test + void multipartFileArray_withNoFiles_returns204() throws Exception { + mockMvc.perform(multipart(CoverageApi.PATH_MULTIPART_FILE_ARRAY)) + .andExpect(status().isNoContent()); + } + + // ==================== formParams tests ==================== + // Covers: application/x-www-form-urlencoded with @RequestParam + + @Test + void formParams_withAllFields_returns204() throws Exception { + mockMvc.perform(post(CoverageApi.PATH_FORM_PARAMS) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param("plain", "plainValue") + .param("bytes", SAMPLE_BYTES_BASE64)) + .andExpect(status().isNoContent()); + } + + @Test + void formParams_withNoFields_returns204() throws Exception { + mockMvc.perform(post(CoverageApi.PATH_FORM_PARAMS) + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) + .andExpect(status().isNoContent()); + } + + // ==================== queryParams tests ==================== + // Covers: query string @RequestParam + + @Test + void queryParams_withAllParams_returns204() throws Exception { + mockMvc.perform(get(CoverageApi.PATH_QUERY_PARAMS) + .param("plain", "queryPlain") + .param("bytes", SAMPLE_BYTES_BASE64)) + .andExpect(status().isNoContent()); + } + + @Test + void queryParams_withNoParams_returns204() throws Exception { + mockMvc.perform(get(CoverageApi.PATH_QUERY_PARAMS)) + .andExpect(status().isNoContent()); + } + + // ==================== pathParams tests ==================== + // Covers: @PathVariable + + @Test + void pathParams_withBothParams_returns204() throws Exception { + mockMvc.perform(get("/coverage/path/{plain}/{bytes}", "pathPlain", SAMPLE_BYTES_BASE64)) + .andExpect(status().isNoContent()); + } + + // ==================== headerParams tests ==================== + // Covers: @RequestHeader + + @Test + void headerParams_withAllHeaders_returns204() throws Exception { + mockMvc.perform(get(CoverageApi.PATH_HEADER_PARAMS) + .header("X-Plain", "headerPlain") + .header("X-Byte", SAMPLE_BYTES_BASE64)) + .andExpect(status().isNoContent()); + } + + @Test + void headerParams_withNoHeaders_returns204() throws Exception { + mockMvc.perform(get(CoverageApi.PATH_HEADER_PARAMS)) + .andExpect(status().isNoContent()); + } + + // ==================== cookieParams tests ==================== + // Covers: @CookieValue + + @Test + void cookieParams_withAllCookies_returns204() throws Exception { + mockMvc.perform(get(CoverageApi.PATH_COOKIE_PARAMS) + .cookie(new Cookie("plain", "cookiePlain")) + .cookie(new Cookie("bytes", SAMPLE_BYTES_BASE64))) + .andExpect(status().isNoContent()); + } + + @Test + void cookieParams_withNoCookies_returns204() throws Exception { + mockMvc.perform(get(CoverageApi.PATH_COOKIE_PARAMS)) + .andExpect(status().isNoContent()); + } + + // ==================== jsonBody tests ==================== + // Covers: @RequestBody with JSON POJO + + @Test + void jsonBody_withValidBody_returns204() throws Exception { + String json = "{\"plain\": \"jsonPlain\", \"bytes\": \"" + SAMPLE_BYTES_BASE64 + "\"}"; + + mockMvc.perform(post(CoverageApi.PATH_JSON_BODY) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andExpect(status().isNoContent()); + } + + @Test + void jsonBody_withEmptyObject_returns204() throws Exception { + mockMvc.perform(post(CoverageApi.PATH_JSON_BODY) + .contentType(MediaType.APPLICATION_JSON) + .content("{}")) + .andExpect(status().isNoContent()); + } + + // ==================== binaryBody tests ==================== + // Covers: @RequestBody with application/octet-stream Resource + + @Test + void binaryBody_withBinaryContent_returns204() throws Exception { + mockMvc.perform(post(CoverageApi.PATH_BINARY_BODY) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .content(SAMPLE_BYTES)) + .andExpect(status().isNoContent()); + } +} + diff --git a/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApi.java index f6fc153c2508..c02fa768c34c 100644 --- a/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApi.java @@ -356,7 +356,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -410,7 +410,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return getDelegate().testEnumParameters(enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString); diff --git a/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java b/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java index da19eea506c4..e9843810956f 100644 --- a/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java +++ b/samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java @@ -207,7 +207,7 @@ default ResponseEntity testClientModel(Client client) { default ResponseEntity testEndpointParameters(BigDecimal number, Double _double, String patternWithoutDelimiter, - byte[] _byte, + String _byte, Integer integer, Integer int32, Long int64, diff --git a/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java index f6fc153c2508..c02fa768c34c 100644 --- a/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java @@ -356,7 +356,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -410,7 +410,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return getDelegate().testEnumParameters(enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString); diff --git a/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java b/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java index da19eea506c4..e9843810956f 100644 --- a/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java +++ b/samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApiDelegate.java @@ -207,7 +207,7 @@ default ResponseEntity testClientModel(Client client) { default ResponseEntity testEndpointParameters(BigDecimal number, Double _double, String patternWithoutDelimiter, - byte[] _byte, + String _byte, Integer integer, Integer int32, Long int64, diff --git a/samples/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java index c4ff183bddcf..9db7408dc15f 100644 --- a/samples/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java @@ -396,7 +396,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -451,7 +451,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java index e41dc080532a..2b8a72c75cbe 100644 --- a/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java @@ -377,20 +377,20 @@ default Mono testClientModel( ) @ResponseStatus(HttpStatus.BAD_REQUEST) default Mono testEndpointParameters( - @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestPart(value = "number", required = true) BigDecimal number, - @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestPart(value = "double", required = true) Double _double, - @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestPart(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestPart(value = "byte", required = true) byte[] _byte, - @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestPart(value = "integer", required = false) Integer integer, - @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestPart(value = "int32", required = false) Integer int32, - @ApiParam(value = "None") @Valid @RequestPart(value = "int64", required = false) Long int64, - @ApiParam(value = "None") @DecimalMax(value = "987.6") @Valid @RequestPart(value = "float", required = false) Float _float, - @ApiParam(value = "None") @Pattern(regexp = "/[a-z]/i") @Valid @RequestPart(value = "string", required = false) String string, + @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, + @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, + @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, + @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, + @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, + @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, + @ApiParam(value = "None") @DecimalMax(value = "987.6") @Valid @RequestParam(value = "float", required = false) Float _float, + @ApiParam(value = "None") @Pattern(regexp = "/[a-z]/i") @Valid @RequestParam(value = "string", required = false) String string, @ApiParam(value = "None") @RequestPart(value = "binary", required = false) Part binary, - @ApiParam(value = "None") @Valid @RequestPart(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, - @ApiParam(value = "None") @Valid @RequestPart(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, - @ApiParam(value = "None") @Size(min = 10, max = 64) @Valid @RequestPart(value = "password", required = false) String password, - @ApiParam(value = "None") @Valid @RequestPart(value = "callback", required = false) String paramCallback, + @ApiParam(value = "None") @Valid @RequestParam(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, + @ApiParam(value = "None") @Valid @RequestParam(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, + @ApiParam(value = "None") @Size(min = 10, max = 64) @Valid @RequestParam(value = "password", required = false) String password, + @ApiParam(value = "None") @Valid @RequestParam(value = "callback", required = false) String paramCallback, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().testEndpointParameters(number, _double, patternWithoutDelimiter, _byte, integer, int32, int64, _float, string, binary, date, dateTime, password, paramCallback, exchange); @@ -436,8 +436,8 @@ default Mono testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, - @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestPart(value = "enum_form_string", required = false) String enumFormString, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().testEnumParameters(enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString, exchange); @@ -540,8 +540,8 @@ default Mono testInlineAdditionalProperties( ) @ResponseStatus(HttpStatus.OK) default Mono testJsonFormData( - @ApiParam(value = "field1", required = true) @Valid @RequestPart(value = "param", required = true) String param, - @ApiParam(value = "field2", required = true) @Valid @RequestPart(value = "param2", required = true) String param2, + @ApiParam(value = "field1", required = true) @Valid @RequestParam(value = "param", required = true) String param, + @ApiParam(value = "field2", required = true) @Valid @RequestParam(value = "param2", required = true) String param2, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().testJsonFormData(param, param2, exchange); diff --git a/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApiDelegate.java b/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApiDelegate.java index 2037e56a08ad..84b558fba08f 100644 --- a/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApiDelegate.java +++ b/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApiDelegate.java @@ -232,7 +232,7 @@ default Mono testClientModel(Mono client, default Mono testEndpointParameters(BigDecimal number, Double _double, String patternWithoutDelimiter, - byte[] _byte, + String _byte, Integer integer, Integer int32, Long int64, diff --git a/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java b/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java index 52c7a008228c..ca9e1b4b1b43 100644 --- a/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java +++ b/samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java @@ -313,8 +313,8 @@ default Mono updatePet( @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) default Mono updatePetWithForm( @NotNull @ApiParam(value = "ID of pet that needs to be updated", required = true) @PathVariable("petId") Long petId, - @ApiParam(value = "Updated name of the pet") @Valid @RequestPart(value = "name", required = false) String name, - @ApiParam(value = "Updated status of the pet") @Valid @RequestPart(value = "status", required = false) String status, + @ApiParam(value = "Updated name of the pet") @Valid @RequestParam(value = "name", required = false) String name, + @ApiParam(value = "Updated status of the pet") @Valid @RequestParam(value = "status", required = false) String status, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().updatePetWithForm(petId, name, status, exchange); diff --git a/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java index 12fca957cad2..c8bb11864ee5 100644 --- a/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java @@ -367,20 +367,20 @@ default Mono> testClientModel( consumes = { "application/x-www-form-urlencoded" } ) default Mono> testEndpointParameters( - @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestPart(value = "number", required = true) BigDecimal number, - @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestPart(value = "double", required = true) Double _double, - @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestPart(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestPart(value = "byte", required = true) byte[] _byte, - @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestPart(value = "integer", required = false) Integer integer, - @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestPart(value = "int32", required = false) Integer int32, - @ApiParam(value = "None") @Valid @RequestPart(value = "int64", required = false) Long int64, - @ApiParam(value = "None") @DecimalMax(value = "987.6") @Valid @RequestPart(value = "float", required = false) Float _float, - @ApiParam(value = "None") @Pattern(regexp = "/[a-z]/i") @Valid @RequestPart(value = "string", required = false) String string, + @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, + @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, + @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, + @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, + @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, + @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, + @ApiParam(value = "None") @DecimalMax(value = "987.6") @Valid @RequestParam(value = "float", required = false) Float _float, + @ApiParam(value = "None") @Pattern(regexp = "/[a-z]/i") @Valid @RequestParam(value = "string", required = false) String string, @ApiParam(value = "None") @RequestPart(value = "binary", required = false) Part binary, - @ApiParam(value = "None") @Valid @RequestPart(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, - @ApiParam(value = "None") @Valid @RequestPart(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, - @ApiParam(value = "None") @Size(min = 10, max = 64) @Valid @RequestPart(value = "password", required = false) String password, - @ApiParam(value = "None") @Valid @RequestPart(value = "callback", required = false) String paramCallback, + @ApiParam(value = "None") @Valid @RequestParam(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, + @ApiParam(value = "None") @Valid @RequestParam(value = "dateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime dateTime, + @ApiParam(value = "None") @Size(min = 10, max = 64) @Valid @RequestParam(value = "password", required = false) String password, + @ApiParam(value = "None") @Valid @RequestParam(value = "callback", required = false) String paramCallback, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().testEndpointParameters(number, _double, patternWithoutDelimiter, _byte, integer, int32, int64, _float, string, binary, date, dateTime, password, paramCallback, exchange); @@ -425,8 +425,8 @@ default Mono> testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, - @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestPart(value = "enum_form_string", required = false) String enumFormString, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().testEnumParameters(enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString, exchange); @@ -526,8 +526,8 @@ default Mono> testInlineAdditionalProperties( consumes = { "application/x-www-form-urlencoded" } ) default Mono> testJsonFormData( - @ApiParam(value = "field1", required = true) @Valid @RequestPart(value = "param", required = true) String param, - @ApiParam(value = "field2", required = true) @Valid @RequestPart(value = "param2", required = true) String param2, + @ApiParam(value = "field1", required = true) @Valid @RequestParam(value = "param", required = true) String param, + @ApiParam(value = "field2", required = true) @Valid @RequestParam(value = "param2", required = true) String param2, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().testJsonFormData(param, param2, exchange); diff --git a/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApiDelegate.java b/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApiDelegate.java index 4cd2a881a8a6..5a4f62ea18b9 100644 --- a/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApiDelegate.java +++ b/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApiDelegate.java @@ -233,7 +233,7 @@ default Mono> testClientModel(Mono client, default Mono> testEndpointParameters(BigDecimal number, Double _double, String patternWithoutDelimiter, - byte[] _byte, + String _byte, Integer integer, Integer int32, Long int64, diff --git a/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java b/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java index e35ec3e59ee1..72b72c92686d 100644 --- a/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java +++ b/samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java @@ -306,8 +306,8 @@ default Mono> updatePet( ) default Mono> updatePetWithForm( @NotNull @ApiParam(value = "ID of pet that needs to be updated", required = true) @PathVariable("petId") Long petId, - @ApiParam(value = "Updated name of the pet") @Valid @RequestPart(value = "name", required = false) String name, - @ApiParam(value = "Updated status of the pet") @Valid @RequestPart(value = "status", required = false) String status, + @ApiParam(value = "Updated name of the pet") @Valid @RequestParam(value = "name", required = false) String name, + @ApiParam(value = "Updated status of the pet") @Valid @RequestParam(value = "status", required = false) String status, @ApiIgnore final ServerWebExchange exchange ) { return getDelegate().updatePetWithForm(petId, name, status, exchange); diff --git a/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApi.java index fda642c0a4e4..a0b036bd55b8 100644 --- a/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApi.java @@ -321,7 +321,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -375,7 +375,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return getDelegate().testEnumParameters(enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString); diff --git a/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java b/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java index 9fe8275b290f..4258bf719ee9 100644 --- a/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java +++ b/samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApiDelegate.java @@ -184,7 +184,7 @@ default ResponseEntity testClientModel(Client body) { default ResponseEntity testEndpointParameters(BigDecimal number, Double _double, String patternWithoutDelimiter, - byte[] _byte, + String _byte, Integer integer, Integer int32, Long int64, diff --git a/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApi.java index fda642c0a4e4..a0b036bd55b8 100644 --- a/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApi.java @@ -321,7 +321,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -375,7 +375,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return getDelegate().testEnumParameters(enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString); diff --git a/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApiDelegate.java b/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApiDelegate.java index 9fe8275b290f..4258bf719ee9 100644 --- a/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApiDelegate.java +++ b/samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApiDelegate.java @@ -184,7 +184,7 @@ default ResponseEntity testClientModel(Client body) { default ResponseEntity testEndpointParameters(BigDecimal number, Double _double, String patternWithoutDelimiter, - byte[] _byte, + String _byte, Integer integer, Integer int32, Long int64, diff --git a/samples/server/petstore/springboot-spring-pageable-without-j8/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-spring-pageable-without-j8/src/main/java/org/openapitools/api/FakeApi.java index bcde37132895..cb63dc4ea9d2 100644 --- a/samples/server/petstore/springboot-spring-pageable-without-j8/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-spring-pageable-without-j8/src/main/java/org/openapitools/api/FakeApi.java @@ -351,7 +351,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -406,7 +406,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-spring-pageable/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-spring-pageable/src/main/java/org/openapitools/api/FakeApi.java index bcde37132895..cb63dc4ea9d2 100644 --- a/samples/server/petstore/springboot-spring-pageable/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-spring-pageable/src/main/java/org/openapitools/api/FakeApi.java @@ -351,7 +351,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -406,7 +406,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-useoptional/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-useoptional/src/main/java/org/openapitools/api/FakeApi.java index 4020a589b44a..a31b015f10e8 100644 --- a/samples/server/petstore/springboot-useoptional/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-useoptional/src/main/java/org/openapitools/api/FakeApi.java @@ -396,7 +396,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Valid @RequestParam(value = "integer", required = false) Optional integer, @ApiParam(value = "None") @Valid @RequestParam(value = "int32", required = false) Optional int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Optional int64, @@ -451,7 +451,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") Optional enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) Optional enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) Optional enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) Optional> enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) Optional> enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) Optional enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-virtualan/src/main/java/org/openapitools/virtualan/api/FakeApi.java b/samples/server/petstore/springboot-virtualan/src/main/java/org/openapitools/virtualan/api/FakeApi.java index e97f35fedc01..d1a899d9c079 100644 --- a/samples/server/petstore/springboot-virtualan/src/main/java/org/openapitools/virtualan/api/FakeApi.java +++ b/samples/server/petstore/springboot-virtualan/src/main/java/org/openapitools/virtualan/api/FakeApi.java @@ -417,7 +417,7 @@ default ResponseEntity testEndpointParameters( @Parameter(name = "number", description = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @Parameter(name = "double", description = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @Parameter(name = "pattern_without_delimiter", description = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @Parameter(name = "byte", description = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @Parameter(name = "integer", description = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @Parameter(name = "int32", description = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @Parameter(name = "int64", description = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -473,7 +473,7 @@ default ResponseEntity testEnumParameters( @Parameter(name = "enum_query_string", description = "Query parameter enum test (string)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @Parameter(name = "enum_query_integer", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @Parameter(name = "enum_query_double", description = "Query parameter enum test (double)", in = ParameterIn.QUERY) @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @Parameter(name = "enum_form_string_array", description = "Form parameter enum test (string array)") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @Parameter(name = "enum_form_string", description = "Form parameter enum test (string)") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot-x-implements-skip/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot-x-implements-skip/src/main/java/org/openapitools/api/FakeApi.java index f7d277c5047b..1c8f167cc04d 100644 --- a/samples/server/petstore/springboot-x-implements-skip/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot-x-implements-skip/src/main/java/org/openapitools/api/FakeApi.java @@ -545,7 +545,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -602,7 +602,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, @ApiParam(value = "") @Valid @RequestParam(value = "enum_query_model_array", required = false) @Nullable List enumQueryModelArray, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); diff --git a/samples/server/petstore/springboot/src/main/java/org/openapitools/api/FakeApi.java b/samples/server/petstore/springboot/src/main/java/org/openapitools/api/FakeApi.java index 6baadd22ffc9..801a0a064c74 100644 --- a/samples/server/petstore/springboot/src/main/java/org/openapitools/api/FakeApi.java +++ b/samples/server/petstore/springboot/src/main/java/org/openapitools/api/FakeApi.java @@ -396,7 +396,7 @@ default ResponseEntity testEndpointParameters( @ApiParam(value = "None", required = true) @DecimalMin(value = "32.1") @DecimalMax(value = "543.2") @Valid @RequestParam(value = "number", required = true) BigDecimal number, @ApiParam(value = "None", required = true) @DecimalMin(value = "67.8") @DecimalMax(value = "123.4") @Valid @RequestParam(value = "double", required = true) Double _double, @ApiParam(value = "None", required = true) @Pattern(regexp = "^[A-Z].*") @Valid @RequestParam(value = "pattern_without_delimiter", required = true) String patternWithoutDelimiter, - @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) byte[] _byte, + @ApiParam(value = "None", required = true) @Valid @RequestParam(value = "byte", required = true) String _byte /* base64 encoded binary */, @ApiParam(value = "None") @Min(value = 10) @Max(value = 100) @Valid @RequestParam(value = "integer", required = false) Integer integer, @ApiParam(value = "None") @Min(value = 20) @Max(value = 200) @Valid @RequestParam(value = "int32", required = false) Integer int32, @ApiParam(value = "None") @Valid @RequestParam(value = "int64", required = false) Long int64, @@ -451,7 +451,7 @@ default ResponseEntity testEnumParameters( @ApiParam(value = "Query parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_query_string", required = false, defaultValue = "-efg") String enumQueryString, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1, -2") @Valid @RequestParam(value = "enum_query_integer", required = false) @Nullable Integer enumQueryInteger, @ApiParam(value = "Query parameter enum test (double)", allowableValues = "1.1, -1.2") @Valid @RequestParam(value = "enum_query_double", required = false) @Nullable Double enumQueryDouble, - @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestPart(value = "enum_form_string_array", required = false) List enumFormStringArray, + @ApiParam(value = "Form parameter enum test (string array)", allowableValues = ">, $", defaultValue = "$") @Valid @RequestParam(value = "enum_form_string_array", required = false) List enumFormStringArray, @ApiParam(value = "Form parameter enum test (string)", allowableValues = "_abc, -efg, (xyz)", defaultValue = "-efg") @Valid @RequestParam(value = "enum_form_string", required = false) String enumFormString ) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);