Repository navigation
[JAVA-SPRING] Convert byte[] to String for operation params [QueryParam; PathParam; HeaderParam; CookieParam; FormParam] - #22930
Conversation
There was a problem hiding this comment.
2 issues found across 41 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java:383">
P2: @RequestPart is for multipart/form-data, but this endpoint consumes application/x-www-form-urlencoded. The modified parameter still uses @RequestPart, so WebFlux won’t bind the form body correctly (likely 400).</violation>
</file>
<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java">
<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java:944">
P2: Form/multipart DTO still asserts `format: byte` as `byte[]`, but Spring’s default data binding does not Base64‑decode form strings to `byte[]`; it converts the string to raw bytes. This makes form DTO binding inconsistent with the new `String` parameter handling and can yield incorrect values without a custom converter.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
2 issues found across 33 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java:16">
P2: RFC3339DateFormat hardcodes the delegate StdDateFormat to UTC and does not override setTimeZone, so any configured timezone will be ignored and dates will always format in UTC.</violation>
<violation number="2" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java:36">
P2: clone() returns the same instance instead of a copy, violating the Format/DateFormat clone contract and preventing callers from obtaining an independent DateFormat instance.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
9 issues found across 87 files
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs">
<violation number="1" location="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs:156">
P2: MarkerArray is compared by contents via CompareNetObjects, but GetHashCode uses List<T>.GetHashCode() (reference-based), violating the Equals/GetHashCode contract for equal instances with different list instances.</violation>
</file>
<file name="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs">
<violation number="1" location="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs:526">
P2: markerArray is serialized with ParameterToString for multipart/form-data, which turns a list of complex objects into a comma-separated ToString output rather than JSON. This likely produces an invalid multipart part for an array of objects; use JSON serialization instead (matching the async method).</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/PathApi.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/PathApi.java:65">
P2: Converted byte-format parameter is now a String without preserving `format: byte` in the @Parameter schema, which causes generated OpenAPI docs/clients to lose the Base64 byte semantics.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java:16">
P2: RFC3339DateFormat extends DateFormat but ignores DateFormat configuration and returns `this` from clone(). Callers that set time zone/leniency will only update the inherited calendar, while the delegate `fmt` stays locked to UTC; and cloning returns a shared mutable instance, breaking expected DateFormat clone semantics and risking shared state across threads.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java:309">
P2: @RequestParam in WebFlux only binds query parameters; using it for application/x-www-form-urlencoded form fields breaks binding of request-body form data.</violation>
<violation number="2" location="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java:351">
P2: Multipart form fields in WebFlux are not bound by @RequestParam; using it for multipart/form-data will ignore request-body fields.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java:666">
P2: @RequestParam in WebFlux binds only query parameters; using it for multipart/form-data fields (additionalMetadata) prevents binding from the request body.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java:316">
P2: In WebFlux, @RequestParam binds query parameters only; with application/x-www-form-urlencoded this will ignore form body fields, so name/status won’t bind for typical POST form submissions.</violation>
<violation number="2" location="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java:359">
P2: @RequestParam in WebFlux binds only query parameters, so additionalMetadata will no longer be read from multipart/form-data. This regresses multipart uploads and should remain @RequestPart.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
Hello @cubic-dev-ai, please rerun the CR. And take into accounts all the passing integration tests I added (they indeed all pass) |
@Picazsoo I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
11 issues found across 97 files
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java:36">
P2: clone() returns the same instance, violating DateFormat’s clone contract and preventing per-thread/per-request clones, which can lead to shared mutable state and ignored configuration in Jackson.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java:428">
P3: Form parameter enum_form_string_array declares a default in @ApiParam but @RequestParam omits defaultValue, so the default isn’t applied and missing values resolve to null.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java:316">
P2: @RequestParam in Spring WebFlux only binds query parameters, so form-urlencoded body fields won’t populate name/status here. With consumes=application/x-www-form-urlencoded, this change can lead to null form values. Use form-data binding via @ModelAttribute or read ServerWebExchange.getFormData()/@RequestBody MultiValueMap instead.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/ApiUtil.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/ApiUtil.java:16">
P2: Response body is always encoded as UTF-8 even when the provided MediaType specifies a different charset, which can cause clients to decode the body incorrectly.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/RFC3339DateFormat.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/RFC3339DateFormat.java:36">
P2: clone() returns `this`, violating the clone contract for mutable DateFormat subclasses and causing callers to share a single mutable instance instead of getting an independent copy.</violation>
</file>
<file name="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs">
<violation number="1" location="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs:156">
P2: GetHashCode uses List.GetHashCode for MarkerArray while Equals performs deep comparison, breaking the equality contract for objects with equivalent list contents.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java:380">
P2: @RequestParam in WebFlux only binds query parameters; for application/x-www-form-urlencoded POST bodies these required form fields will not bind, leading to missing-parameter 400s.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/SpringDocConfiguration.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/SpringDocConfiguration.java:21">
P3: API title in generated SpringDoc config is HTML-escaped ("&") and no longer matches the source OpenAPI spec, leading to an incorrect title in the generated OpenAPI/Swagger UI output.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java:72">
P2: The InputStream from `resource.getInputStream()` is never closed and the blocking `readAllBytes` runs on the subscriber thread (no boundedElastic scheduler). This can leak file descriptors and block the Netty event loop in WebFlux.</violation>
<violation number="2" location="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java:194">
P2: DataBuffer instances from multipart Part content are consumed but never released, which can leak pooled Netty buffers under load. Release buffers after reading (DataBufferUtils.release) or use releaseConsumer to avoid native memory leaks.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java:309">
P2: In Spring WebFlux, @RequestParam only binds query parameters, so using it for application/x-www-form-urlencoded body fields will leave name/status null for typical form submissions. This breaks the form update endpoint.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| ServerHttpResponse response = exchange.getResponse(); | ||
| response.getHeaders().setContentType(mediaType); | ||
|
|
||
| byte[] exampleBytes = example.getBytes(StandardCharsets.UTF_8); |
There was a problem hiding this comment.
P2: Response body is always encoded as UTF-8 even when the provided MediaType specifies a different charset, which can cause clients to decode the body incorrectly.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/ApiUtil.java, line 16:
<comment>Response body is always encoded as UTF-8 even when the provided MediaType specifies a different charset, which can cause clients to decode the body incorrectly.</comment>
<file context>
@@ -0,0 +1,20 @@
+ 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));
</file context>
There was a problem hiding this comment.
8 issues found across 97 files
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/SpringDocConfiguration.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/configuration/SpringDocConfiguration.java:21">
P3: OpenAPI title is HTML-escaped in a Java string literal, so the title will render as "&" instead of "&".</violation>
</file>
<file name="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs">
<violation number="1" location="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Model/MultipartMixedRequest.cs:156">
P2: GetHashCode uses List<T>.GetHashCode() for MarkerArray, which is reference-based, while Equals performs deep comparison via Compare.NET Objects. This breaks the equality/hash code contract for equal instances with equivalent list contents and can misbehave in Dictionary/HashSet.</violation>
</file>
<file name="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java">
<violation number="1" location="samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java:316">
P2: In Spring WebFlux, @RequestParam only binds query parameters. For application/x-www-form-urlencoded POSTs, these parameters come from the request body, so name/status will not bind and will be null. Use @ModelAttribute or @RequestBody form data binding instead.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/RFC3339DateFormat.java:36">
P2: RFC3339DateFormat.clone() returns the same mutable instance, violating the DateFormat/Cloneable contract and causing shared state when callers clone the formatter (e.g., for thread safety).</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java:51">
P2: Unclosed InputStream and blocking I/O in `Mono.fromCallable` can leak resources and block the WebFlux event loop. Use try-with-resources to close the stream and offload blocking reads to `Schedulers.boundedElastic()`.</violation>
<violation number="2" location="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java:194">
P2: Reactive multipart handlers consume DataBuffer instances without releasing them, which can leak pooled buffers in WebFlux.</violation>
</file>
<file name="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs">
<violation number="1" location="samples/client/others/csharp-complex-files/src/Org.OpenAPITools/Api/MultipartApi.cs:526">
P2: markerArray is serialized with ParameterToString in multipart requests, which calls ToString on each complex object and produces a debug string rather than JSON. This likely sends invalid data for a list of MultipartMixedRequestMarker objects.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/RFC3339DateFormat.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/RFC3339DateFormat.java:36">
P2: clone() returns `this`, breaking the DateFormat clone contract and causing shared mutable state; this defeats thread-safe use of DateFormat clones.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| } | ||
|
|
||
| private Mono<Void> verifyBase64Content(String base64Value, String fieldName) { | ||
| try { |
There was a problem hiding this comment.
P2: Unclosed InputStream and blocking I/O in Mono.fromCallable can leak resources and block the WebFlux event loop. Use try-with-resources to close the stream and offload blocking reads to Schedulers.boundedElastic().
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/springboot-byte-format-edge-cases-reactive/src/main/java/org/openapitools/api/CoverageApiTestControllerImpl.java, line 51:
<comment>Unclosed InputStream and blocking I/O in `Mono.fromCallable` can leak resources and block the WebFlux event loop. Use try-with-resources to close the stream and offload blocking reads to `Schedulers.boundedElastic()`.</comment>
<file context>
@@ -0,0 +1,415 @@
+ }
+
+ private Mono<Void> verifyBase64Content(String base64Value, String fieldName) {
+ try {
+ byte[] decoded = Base64.getDecoder().decode(base64Value);
+ logger.debug("Base64 decoded successfully for field: {}", fieldName);
</file context>
…ration-params-to-String # Conflicts: # .github/workflows/samples-spring.yaml # modules/openapi-generator/src/main/resources/JavaSpring/pathParams.mustache # modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java # samples/server/petstore/springboot-beanvalidation-no-nullable/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-beanvalidation/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-builtin-validation/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/PetApi.java # samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/PetApi.java # samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-spring-pageable-without-j8/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-spring-pageable/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-useoptional/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-x-implements-skip/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot/src/main/java/org/openapitools/api/FakeApi.java
…-convert-byte-array-operation-params-to-String # Conflicts: # modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java # modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache # modules/openapi-generator/src/main/resources/JavaSpring/queryParams.mustache # modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java # modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java # modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java # samples/client/petstore/spring-http-interface-bean-validation/src/main/java/org/openapitools/api/FakeApi.java # samples/client/petstore/spring-http-interface-reactive-bean-validation/src/main/java/org/openapitools/api/FakeApi.java # samples/client/petstore/spring-http-interface-springboot-4/src/main/java/org/openapitools/api/FakeApi.java # samples/client/petstore/spring-http-interface-useHttpServiceProxyFactoryInterfacesConfigurator/src/main/java/org/openapitools/api/FakeApi.java # samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/FakeApi.java # samples/openapi3/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java # samples/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/spring-boot-defaultInterface-unhandledExcp/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-beanvalidation-no-nullable/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-beanvalidation/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-builtin-validation/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-delegate-j8/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-delegate/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-include-http-request-context/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-reactive-noResponseEntity/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-reactive/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-spring-pageable-delegatePattern-without-j8/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-spring-pageable-delegatePattern/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-spring-pageable-without-j8/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-spring-pageable/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-useoptional/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot-virtualan/src/main/java/org/openapitools/virtualan/api/FakeApi.java # samples/server/petstore/springboot-x-implements-skip/src/main/java/org/openapitools/api/FakeApi.java # samples/server/petstore/springboot/src/main/java/org/openapitools/api/FakeApi.java
There was a problem hiding this comment.
1 existing issue remains and 3 new issues found across 104 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="samples/server/petstore/springboot-byte-format-edge-cases/README.md">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/README.md:16">
P3: These examples cannot compile against this sample because it exposes `CoverageApi`, not `PetApi`. Update the examples to use the sample's actual API or remove the unrelated Petstore boilerplate.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases/pom.xml">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/pom.xml:27">
P2: This build omits `spring-boot-maven-plugin`, so `mvn package` produces a plain JAR instead of a launchable Spring Boot archive. Add the plugin as in the existing Spring Boot sample.</violation>
</file>
<file name="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApi.java">
<violation number="1" location="samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApi.java:311">
P2: Standard Base64 values can contain `/`, but this route puts `bytes` in one path segment; a literal slash changes the route, and the default Spring Boot/Tomcat setup rejects an encoded `%2F`. Use a URL-safe representation for path values or keep arbitrary binary parameters out of the path.</violation>
</file>
Requires human review: Auto-approval blocked because this review re-detected 5 unresolved issues already reported by Cubic.
Re-trigger cubic
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-source-plugin</artifactId> |
There was a problem hiding this comment.
P2: This build omits spring-boot-maven-plugin, so mvn package produces a plain JAR instead of a launchable Spring Boot archive. Add the plugin as in the existing Spring Boot sample.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/springboot-byte-format-edge-cases/pom.xml, line 27:
<comment>This build omits `spring-boot-maven-plugin`, so `mvn package` produces a plain JAR instead of a launchable Spring Boot archive. Add the plugin as in the existing Spring Boot sample.</comment>
<file context>
@@ -0,0 +1,84 @@
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
</file context>
There was a problem hiding this comment.
This is intentional. pom-sb3.mustache gates the plugin behind
{{^interfaceOnly}}, and this sample is generated with interfaceOnly: true (it
is a library-style interface/DTO sample, not meant to be packaged and run as a
launchable Spring Boot application on its own). The same pattern already exists in
several other pre-existing samples, including
spring-boot-defaultInterface-unhandledExcp, spring-boot-nullable-set, and
springboot-paged-model. No change made.
| } | ||
|
|
||
|
|
||
| String PATH_PATH_PARAMS = "/coverage/path/{plain}/{bytes}"; |
There was a problem hiding this comment.
P2: Standard Base64 values can contain /, but this route puts bytes in one path segment; a literal slash changes the route, and the default Spring Boot/Tomcat setup rejects an encoded %2F. Use a URL-safe representation for path values or keep arbitrary binary parameters out of the path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/springboot-byte-format-edge-cases/src/main/java/org/openapitools/api/CoverageApi.java, line 311:
<comment>Standard Base64 values can contain `/`, but this route puts `bytes` in one path segment; a literal slash changes the route, and the default Spring Boot/Tomcat setup rejects an encoded `%2F`. Use a URL-safe representation for path values or keep arbitrary binary parameters out of the path.</comment>
<file context>
@@ -0,0 +1,366 @@
+ }
+
+
+ String PATH_PATH_PARAMS = "/coverage/path/{plain}/{bytes}";
+ /**
+ * GET /coverage/path/{plain}/{bytes}
</file context>
There was a problem hiding this comment.
This is a valid observation, but it describes an inherent property
of standard Base64 combined with using a value as a single path segment, not a
codegen defect. Standard Base64's alphabet includes /, which is a reserved
path-segment delimiter. Fixing this in generated code would require either
deviating from standard Base64 encoding (breaking OpenAPI spec compliance for
format: byte) or refusing to generate valid, if inadvisable, API designs that
put arbitrary binary data in a path segment. Since this specific edge case is
exercised by a test spec that this PR added, I added a documentation caveat
directly above the affected path parameter in byte-format-edge-cases.yaml,
describing the limitation and recommending against putting arbitrary Base64
values in path segments (or enabling encoded-slash handling on the server if a
caller depends on it). No behavioral or generator code change was made.
| by adding ```@Controller``` classes that implement the interface. Eg: | ||
| ```java | ||
| @Controller | ||
| public class PetController implements PetApi { |
There was a problem hiding this comment.
P3: These examples cannot compile against this sample because it exposes CoverageApi, not PetApi. Update the examples to use the sample's actual API or remove the unrelated Petstore boilerplate.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/springboot-byte-format-edge-cases/README.md, line 16:
<comment>These examples cannot compile against this sample because it exposes `CoverageApi`, not `PetApi`. Update the examples to use the sample's actual API or remove the unrelated Petstore boilerplate.</comment>
<file context>
@@ -0,0 +1,27 @@
+by adding ```@Controller``` classes that implement the interface. Eg:
+```java
+@Controller
+public class PetController implements PetApi {
+// implement all PetApi methods
+}
</file context>
There was a problem hiding this comment.
This is the standard interfaceOnly boilerplate produced by the
shared README.mustache template, and it is not specific to this sample. The
exact same generic PetApi usage example appears verbatim in the README of the
same pre-existing interfaceOnly samples referenced above (and others). It is a
long-standing, generator-wide documentation gap for the interfaceOnly mode, not
something introduced by this PR. No change made here; a fix would need to update
the shared template for all interfaceOnly samples at once.
- Close unclosed InputStream in blocking CoverageApiTestControllerImpl - Rename misleading Kotlin parity test to reflect blocking-mode coverage - Revert an incorrectly-renamed pre-existing Java test (...AsRequestParam back to ...AsRequestPart) - Centralize the "/* base64 encoded binary */" comment into optionalDataType.mustache so it appears consistently across api, apiController, apiDelegate, and spring-http-interface templates (previously only duplicated in the per-location param partials) - Add a "(base64 encoded)" note to the shared @PARAM Javadoc line for the same set of templates - Extend convertByteArrayParamsToStringType to also convert array-of-byte params (List<byte[]> -> List<String>), since Spring cannot bind base64 array elements correctly either - Make the multipart/form-data media-type check case-insensitive (RFC 7231) - Fix reactive CoverageApiTestControllerImpl.multipartSimple/ multipartSimpleValidated to reuse verifyBase64Content so a content-mismatch error is no longer mislabeled as "Invalid base64" - Remove dead null/empty checks after MultipartMixedStatus.fromValue() (it only throws, never returns null) - Document the base64-in-path-segment caveat (values may contain '/') directly on the CoverageApi path-param operation description - Make the spring-boot library README mention Spring-WebFlux instead of Spring-MVC when reactive is enabled in interfaceOnly mode Regenerated all affected samples (73 JavaSpring-template configs) to verify only the intended comment/Javadoc/README changes were produced. Verified with the full SpringCodegenTest (373) and KotlinSpringServerCodegenTest (275) suites, plus mvn compile of both byte-format-edge-cases samples and the spring-http-interface sample. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- RFC3339DateFormat.clone() in both byte-format-edge-cases samples now delegates to super.clone() instead of returning 'this', fixing a Cloneable/DateFormat contract violation flagged by review. - Reactive CoverageApiTestControllerImpl.binaryBody now closes the request-body InputStream via try-with-resources. - Reactive CoverageApiTestControllerImpl no longer leaks pooled DataBuffer instances: added a joinAndReleaseBuffers helper that releases each buffer after reading, used by multipartFileArray, multipartMixed, and multipartSimpleValidated. - Fixed the HTML-escaped title in SpringDocConfiguration.java for the blocking sample (Multipart & Byte Edge Case Coverage -> Multipart & Byte Edge Case Coverage). This file is hand-maintained (not reproduced by the sample's own interfaceOnly generator config), so it needed a direct, one-off fix rather than a spec/template change. Remaining review findings (ApiUtil.java UTF-8 encoding, csharp-complex-files Equals/GetHashCode and markerArray serialization, missing spring-boot-maven-plugin, README PetApi boilerplate, base64-in-path-segment) were investigated and found to be pre-existing, generator-wide behavior unrelated to this PR's scope, or intentional given the sample's configuration; rationale documented separately. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
I added implementation of the generated interface to serve as a counterpart to the tests that I also implemented.
There was a problem hiding this comment.
I added tests to verify that the generated code actually works. As far as I can tell, these tests are in fact executed as a part of the build.
There was a problem hiding this comment.
I added implementation of the generated interface to serve as a counterpart to the tests that I also implemented.
| consumes = { "multipart/form-data" } | ||
| ) | ||
| default Mono<ResponseEntity<Void>> multipartMixed( | ||
| @Parameter(name = "status", description = "", required = true) @Valid @RequestPart(value = "status", required = true) String /* MultipartMixedStatus */ status, |
There was a problem hiding this comment.
in webflux it is not possible to decode to the enum and the parameter has to be of type String.
Hence I am adding a conditional inline comment /* MultipartMixedStatus */ via mustache lambda to hint what it actually represents.
| by adding ```@Controller``` classes that implement the interface. Eg: | ||
| ```java | ||
| @Controller | ||
| public class PetController implements PetApi { |
There was a problem hiding this comment.
This is the standard interfaceOnly boilerplate produced by the
shared README.mustache template, and it is not specific to this sample. The
exact same generic PetApi usage example appears verbatim in the README of the
same pre-existing interfaceOnly samples referenced above (and others). It is a
long-standing, generator-wide documentation gap for the interfaceOnly mode, not
something introduced by this PR. No change made here; a fix would need to update
the shared template for all interfaceOnly samples at once.
|
Hey @cubic-dev-ai. Please re-review |
@Picazsoo I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
1 issue found across 111 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/FakeApi.java">
<violation number="1" location="samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/FakeApi.java:224">
P3: This conversion normalizes every text field in `testEndpointParameters` to `@RequestParam`, but the file field `binary` directly below remains an unconditional `@RequestPart ... Part`, in a method whose content type is pinned to `application/x-www-form-urlencoded`. A `Part`/`MultipartFile` can only be encoded as multipart, so a generated client cannot transmit `binary` for the declared content type, and the file parameter is effectively non-bindable/never received for urlencoded requests. The root cause is in the generator template `modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache`: the `{{#isFile}}` branch emits `@RequestPart ... Part/MultipartFile` unconditionally, while `markMultipartFormDataParameters` only switches reactive text fields based on media type. Gate the file-part annotation on the operation consuming `multipart/form-data`; otherwise emit `@RequestParam {{{dataType}}}` for the file field as well.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| @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 */, |
There was a problem hiding this comment.
P3: This conversion normalizes every text field in testEndpointParameters to @RequestParam, but the file field binary directly below remains an unconditional @RequestPart ... Part, in a method whose content type is pinned to application/x-www-form-urlencoded. A Part/MultipartFile can only be encoded as multipart, so a generated client cannot transmit binary for the declared content type, and the file parameter is effectively non-bindable/never received for urlencoded requests. The root cause is in the generator template modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache: the {{#isFile}} branch emits @RequestPart ... Part/MultipartFile unconditionally, while markMultipartFormDataParameters only switches reactive text fields based on media type. Gate the file-part annotation on the operation consuming multipart/form-data; otherwise emit @RequestParam {{{dataType}}} for the file field as well.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/spring-http-interface-reactive/src/main/java/org/openapitools/api/FakeApi.java, line 224:
<comment>This conversion normalizes every text field in `testEndpointParameters` to `@RequestParam`, but the file field `binary` directly below remains an unconditional `@RequestPart ... Part`, in a method whose content type is pinned to `application/x-www-form-urlencoded`. A `Part`/`MultipartFile` can only be encoded as multipart, so a generated client cannot transmit `binary` for the declared content type, and the file parameter is effectively non-bindable/never received for urlencoded requests. The root cause is in the generator template `modules/openapi-generator/src/main/resources/JavaSpring/formParams.mustache`: the `{{#isFile}}` branch emits `@RequestPart ... Part/MultipartFile` unconditionally, while `markMultipartFormDataParameters` only switches reactive text fields based on media type. Gate the file-part annotation on the operation consuming `multipart/form-data`; otherwise emit `@RequestParam {{{dataType}}}` for the file field as well.</comment>
<file context>
@@ -218,20 +218,20 @@ Mono<ResponseEntity<Client>> testClientModel(
+ @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,
</file context>
- SpringCodegen.java: only log byte[]->String parameter conversions when the operation actually had any (avoids INFO-level log spam for every operation), and lower the log level to debug. - SpringCodegenTest.java: add an assertion that the JSON body operation's request parameter stays typed as FormParamsRequest (the model the InlineModelResolver deduplicates the JSON body's inline schema into), covering the previously-unchecked byte[] JSON body case. - csharp/api.mustache and csharp/ApiClient.mustache: make the multipart/form-data content-type checks case-insensitive, so the mixed-case 'Multipart/Form-Data' test operation (added earlier in this PR to validate cross-generator case-insensitive media-type handling) is actually sent as multipart/form-data by the C# httpclient/restsharp client. Regenerated csharp-complex-files to pick up the fix. - Reactive CoverageApiTestControllerImpl.multipartSimple: read and release the file part's DataBuffers via the existing joinAndReleaseBuffers helper instead of dropping them unread, fixing a pooled-buffer leak. Also investigated and found pre-existing/out-of-scope (rationale updated in the review rebuttal doc): MultipartApi.cs convenience methods dropping operationIndex (generator-wide, unrelated to byte-format/media-type handling), and spring-http-interface-reactive FakeApi.java's binary parameter keeping @RequestPart in a urlencoded operation (identical mismatch already present on master in the blocking spring-http-interface sample). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
1 issue found across 92 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java">
<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java:1280">
P2: This assertion does not catch conversion of a JSON-body `byte[]` parameter because the fixture's body parameter is an object model. Add a scalar `format: byte` JSON body case and assert its generated parameter remains `byte[]`.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| JavaFileAssert.assertThat(files.get("JsonBodyApi.java")) | ||
| .assertMethod("jsonBody") | ||
| .assertParameter("formParamsRequest") | ||
| .hasType("FormParamsRequest"); |
There was a problem hiding this comment.
P2: This assertion does not catch conversion of a JSON-body byte[] parameter because the fixture's body parameter is an object model. Add a scalar format: byte JSON body case and assert its generated parameter remains byte[].
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java, line 1280:
<comment>This assertion does not catch conversion of a JSON-body `byte[]` parameter because the fixture's body parameter is an object model. Add a scalar `format: byte` JSON body case and assert its generated parameter remains `byte[]`.</comment>
<file context>
@@ -1268,6 +1268,17 @@ public void shouldHandleFormatByteCorrectlyForAllApiParametersAndProperties() th
+ JavaFileAssert.assertThat(files.get("JsonBodyApi.java"))
+ .assertMethod("jsonBody")
+ .assertParameter("formParamsRequest")
+ .hasType("FormParamsRequest");
+
// Binary request body: bound as Resource for streaming
</file context>
Move the markerArray property and /multipart-mixed-case-media-type operation (added by this branch for cross-generator case-insensitive media-type coverage) out of the shared form-multipart-binary-array.yaml fixture and into a new, dedicated form-multipart-binary-array-extended.yaml spec. - form-multipart-binary-array.yaml is restored to its pristine master content, so every consumer other than the tests that need the new coverage (Python FastAPI, TS Inversify/Axios, Java Jersey, JAX-RS spec, JavaScript, and the C# restsharp complexfiles sample) is unaffected. - SpringCodegenTest (testMultipartBoot, testReactiveMultipartBoot) and JavaClientCodegenTest (testRestClientFormMultipart, testWebClientWithUseAbstractionForFiles, testRestClientWithUseAbstractionForFiles, testMicroprofileFormMultipartArray) now point at the new extended spec, since their assertions depend on markerArray. - Reverted csharp/api.mustache and csharp/ApiClient.mustache to master; the case-insensitive content-type check is no longer needed since the C# generator never sees a mixed-case media type again. - Reverted samples/client/others/csharp-complex-files and all other regenerated C# restsharp samples back to their pristine master state (zero diff against master). - Updated PR-22930-review-rebuttal.md items covering the C# findings to note they are no longer part of this PR's diff. Verified: SpringCodegenTest (373/373), JavaClientCodegenTest (293/293), KotlinSpringServerCodegenTest, and all other incidental spec consumers pass. git diff master against every reverted C# file and sample returns zero lines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e-format fix Generator/template changes: - Revert reactive multipart annotation logic in formParams.mustache back to unconditional @RequestPart for the array-non-model and scalar branches, matching master exactly. This fixes a compile-breaking type mismatch where the delegate/bridge methods declared a different type than the annotated method for non-byte scalar form fields in reactive multipart operations. Blocking (non-reactive) array params keep the newer, tested @RequestParam behavior. - Remove the now-unused lambdaTypeComment Mustache lambda from SpringCodegen.java (its only call site was removed with the above fix). - Add @Schema(type = "string", format = "byte") to paramDoc.mustache for non-array isByteArray parameters, so springdoc-generated API docs keep documenting the Base64 format contract after byte[] -> String conversion. - Gate the Feign-client example in the spring-boot README template behind {{^reactive}}, since Spring Cloud OpenFeign does not support reactive Mono/Flux return types. Sample changes (regenerated, plus two manually-maintained coverage controllers): - Reactive Fake/Pet API samples: annotation diffs reverted to match master, only byte-format-related diffs remain. - 16 FakeApi.java samples across Spring variants: gained the new @Schema(format = "byte") on byte parameters. - springboot-byte-format-edge-cases(-reactive): reverted the RFC3339DateFormat clone() hand-edit back to match the (separately pre-existing, unfixed) shared template; removed Feign example from the reactive README. - CoverageApiTestControllerImpl.java (blocking + reactive): replaced unbounded buffering with a bounded inputStream.readNBytes() read in binaryBody (removing the duplicate readAllBytes helper); scheduled the reactive binaryBody's blocking read on Schedulers.boundedElastic(); released DataBuffers incrementally in the reactive multipartSimple instead of collecting them into a discarded byte[]. Investigated and confirmed as invalid, out of scope, or already correct (documented in PR-review-rebuttal-round2.md, not committed here): - README PetApi/CoverageApi name mismatch: same generic boilerplate as 10+ other samples, pre-existing template limitation. - Missing spring-boot-maven-plugin in interfaceOnly pom.xml: intentionally gated behind {{^interfaceOnly}}, consistent with all other interfaceOnly samples. - multipartFileArray "unused" byte array: actually used for content comparison against expectedContents[i]. - java-camel stale version header: root-caused to OpenAPI Generator's built-in "test files are never overwritten by regeneration" behavior; confirmed pre-existing on master (7.11.0-SNAPSHOT there) and reproducible as a TemplateManager "Skipped" log line, unrelated to this PR and not fixable by regeneration. Verified via full SpringCodegenTest/JavaClientCodegenTest/ KotlinSpringServerCodegenTest suites (953 tests, 0 failures), a full regeneration diff of all Spring/kotlin-spring bin/configs, mvn compile/test on both byte-format-edge-cases samples, and live curl checks against running blocking and reactive servers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Correctly mapping OpenAPI
format: bytefor the Java Spring generatorFixes: #22898
Scope:
SpringCodegen.java(Java client/server) —spring-boot,spring-cloud(Feign),spring-http-interfacelibraries.kotlin-springis not covered (see "Known gaps" below).1. The problem
The OpenAPI Specification defines
type: string, format: byteas "base64 encoded characters" — i.e. the wire value is always a base64 string, and it is the application's job to decode/encode it to actual bytes:Before this fix, the Java Spring generator mapped
format: bytetobyte[]everywhere a byte-format value could appear: in the JSON body, and also in query, path, header, cookie, and form parameters. That mapping is only actually correct for one of those locations.Why
byte[]works for a JSON request/response bodyWhen
format: byteappears on a DTO field serialized by Jackson (the JSON body case), Jackson'sObjectMapperautomatically base64-encodes/decodesbyte[]fields using its defaultBase64Variant(MIME_NO_LINEFEEDS). This is standard, well-documented Jackson behavior — see the Jackson databind Javadoc for binary/byte[] handling andBase64Variants. Sobyte[]in a JSON body is genuinely correct and needs no change — the framework does the base64 work for you.Why
byte[]is wrong for query/path/header/cookie/form paramsQuery, path, header, cookie, and form-urlencoded parameters are not deserialized by Jackson at all. Spring MVC/WebFlux binds these using its general-purpose
ConversionService(@RequestParam,@PathVariable,@RequestHeader,@CookieValue— see Spring's type conversion documentation and the@RequestParamreference).I decompiled
spring-core-6.2.18.jarto see exactly what the defaultConversionServicedoes with abyte[]target/source, and confirmed the registered converter isorg.springframework.core.convert.support.ArrayToStringConverter(and its inverse,StringToArrayConverter). Its logic is:So a byte array such as
{104, 101, 108, 108, 111}("hello") is not base64-encoded by this path — it is rendered as the literal string"104,101,108,108,111"(decimal byte values joined by commas). The reverse conversion (StringToArrayConverter, incoming request → controller method param) expects that same comma-separated decimal format, not base64.Consequence of the old behavior: any client sending a real base64 string (as the OpenAPI spec requires) into a query/path/header/cookie/form parameter typed
byte[]would fail to bind correctly (Spring would try to parse the base64 string as comma-separated integers and typically throw a conversion exception), and any server emitting abyte[]into one of these locations would not actually produce valid base64 on the wire. Thebyte[]type was misleading — it implied "correctly typed bytes," but no component in the request pipeline for these locations understood base64.2. The fix
2.1
convertByteArrayParamsToStringType(operation)For every parameter on an operation whose location is not the request body (
queryParams,pathParams,headerParams,cookieParams,formParams) and whose OpenAPI type isstring, format: byte, the generator now rewrites the generated JavadataTypefrombyte[]toString. A short code comment (/* base64 encoded binary */) is emitted next to the parameter in the generated method signature so the base64 contract is visible to anyone reading the generated code.This means:
spring-http-interface, RestTemplate/WebClient-based clients) must now pass an already-base64-encodedString, e.g.Base64.getEncoder().encodeToString(bytes), instead of a rawbyte[].Stringas-is and must decode it themselves, e.g.Base64.getDecoder().decode(value), when they need the actual bytes.This is intentionally symmetrical with what a hand-written Spring application would have to do anyway, since Spring's
ConversionServicewas never going to do this for you correctly.2.2
markMultipartFormDataParameters(operation)(reactive/WebFlux only)Spring WebFlux does not support the same MVC-style binding for
multipart/form-datatext fields — WebFlux typically needs@RequestPart(bound to aPart/Mono<Part>) for all parts of a multipart request, including plain text fields, whereas Spring MVC can bind simple text fields with a plain@RequestParam. This method flags each non-file multipart field with the vendor extensionx-isMultipartFormDataso the mustache templates can:@RequestPart(not@RequestParam) for reactive text fields, andString(orFlux<String>/List<String>for repeated/array fields) rather than the raw model type, consistent with how WebFlux exposes multipart text parts.File parts (
format: binary) are unaffected by either method and keep the framework's native multipart abstraction —MultipartFilefor Spring MVC,Part/FilePartfor WebFlux — since these already stream raw bytes correctly with no base64 involved.2.3 Summary of the resulting type mapping
string, format: byteStringstring, format: byteor plainstringStringstring, format: binaryMultipartFile(MVC) /Part(WebFlux)string, format: bytebyte[]application/octet-streambodystring, format: binaryResourceThis preserves the important distinction the OpenAPI spec makes between
format: byte(base64 text) andformat: binary(raw bytes), rather than collapsing both intobyte[]regardless of transport location.3. Why this is correct (not just "different")
byte[]typing for params was already broken, not merely stylistic. See the decompiledArrayToStringConverterbehavior in §1 — Spring's default conversion never implemented base64 for these locations, so abyte[]in a query/path/header/cookie/form parameter round-tripped through decimal-CSV, not base64. This is confirmed by direct bytecode inspection ofspring-core, not conjecture.HttpMessageConverterpath (JSON body) is the only place in the stack that base64-encodesbyte[]automatically. Everywhere else, Spring intentionally leaves conversion to whateverConverter<S,T>is registered, and none is registered for base64. Typing the generated parameter asStringaccurately reflects this framework boundary instead of hiding it behind abyte[]that silently didn't work.byte[]to a generated Feign/http-interface/WebClient method for one of these locations must now pass a base64String. This is source-incompatible, but the previous behavior was not actually functioning end-to-end, so there is no working call pattern being broken — only incorrect code that either never compiled against real usage or silently sent corrupt data.4. Verification performed (this session)
4.1 Unit / codegen tests
SpringCodegenTest.shouldHandleFormatByteCorrectlyForAllApiParametersAndProperties(drivesbyte-format-baseline.yaml) — asserts the exact type mapping table in §2.3 for every param location and for JSON/binary bodies.SpringCodegenTest.testMultipartBoot/testReactiveMultipartBoot,JavaClientCodegenTestmultipart tests,KotlinSpringServerCodegenTest— all passing after the master merge (953 targeted tests, 0 failures).4.2 Real generated sample projects (compiled + integration-tested)
samples/server/petstore/springboot-byte-format-edge-cases(Spring MVC, blocking) — 21 integration tests (MockMvc), 0 failures.samples/server/petstore/springboot-byte-format-edge-cases-reactive(WebFlux) — 22 integration tests (WebTestClient), 0 failures.CoverageApiTestControllerImpl) that base64-decodes incoming values and compares against known expected byte content, so the tests validate actual data correctness, not just type-compatibility.4.3 Live end-to-end
curlverification (both MVC and WebFlux servers actually running)Ran both sample apps live (
mvn spring-boot:run, blocking on Tomcat and reactive on Netty) and exercised every location by hand:204; base64 of the wrong content →500(proves the server genuinely decodes and content-checks, not just accepts any string).statusArrayvia@RequestParamand JSONmarkerArrayvia@RequestPart) →204for both blocking and reactive.application/octet-streambody: correct bytes →204; wrong bytes →500.@RequestPart/Flux<String>handling inmarkMultipartFormDataParametersworks correctly, not just compiles.4.4 Client-side libraries (Feign /
spring-http-interface)Regenerated
byte-format-baseline.yamlwith--library spring-cloudand--library spring-http-interfacevia the built CLI jar:Stringwith the base64 comment, exactly as in thespring-bootserver case.fileparameters remainMultipartFilewith@RequestPart, and text fields become@RequestParam String.mvn compile, zero errors) — the change does not break Feign contract parsing or the Spring 6@HttpExchange-based declarative HTTP interface generation. Both share the exact sameSpringCodegen.postProcessOperationsWithModels()code path asspring-boot, so there is no separate logic path that could diverge.4.5 Known gap identified (not fixed by this branch)
kotlin-springuses a separate codegen class,KotlinSpringServerCodegen(extends AbstractKotlinCodegen, notSpringCodegen), with its own template set. Regenerating the same spec with-g kotlin-springconfirmed the query parameter is still generated asbytes: kotlin.ByteArray?— i.e. the same underlying bug (§1) still exists there. Porting this fix to Kotlin would be a separate, follow-up change; it is out of scope for this PR/branch.5. References
format: bytedefinition: https://swagger.io/docs/specification/data-models/data-types/#stringConversionService: https://docs.spring.io/spring-framework/reference/core/validation/convert.html@RequestParam: https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/requestparam.htmlMultipartFile,@RequestPart): https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet/multipart.htmlPart,@RequestPart): https://docs.spring.io/spring-framework/reference/web/webflux/multipart.htmlbyte[]) base64 handling: https://fasterxml.github.io/jackson-databind/javadoc/2.15/com/fasterxml/jackson/databind/ObjectMapper.htmlPR checklist
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*.IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
master(upcoming7.x.0minor release - breaking changes with fallbacks),8.0.x(breaking changes without fallbacks)"fixes #123"present in the PR description)Summary by cubic
Converts
byte[]operation parameters toStringin the Java Spring generator for query, path, header, cookie, and form to fix base64 handling and align generated types with the OpenAPI spec. Also fixes multipart binding edge cases and adds MVC/WebFlux samples and tests to cover them.Bug Fixes
byteand array-of-byteparams toString/List<String>inSpringCodegen; add the base64 comment vialambdaTypeCommentand a "(base64 encoded)" note in the shared@paramJavadoc.byte[]in models and JSON bodies,Resourceforapplication/octet-stream,MultipartFile/Partfor multipart files; reactive non-file form params now use@RequestParam.CoverageApiendpoints and new MVC/WebFlux edge-case samples with CI generation.RFC3339DateFormatforces UTC, uses a per-callStdDateFormat, and itsclone()returns a proper copy; reactive sample controllers close request streams and release pooledDataBufferinstances.form-multipart-binary-array-extended.yamlspec so the shared fixture and C# restsharp client remain unchanged.Migration
byte[]for these params, decode the provided base64Stringyourself (e.g.,Base64.getDecoder().decode(value)).Written for commit 53e80e5. Summary will update on new commits.