Skip to content

fix(java): place bean-validation @Valid on the type argument instead of the container (HV000271) - #24176

Open
twonky4 wants to merge 1 commit into
OpenAPITools:masterfrom
twonky4:fix/hv000271-java
Open

fix(java): place bean-validation @Valid on the type argument instead of the container (HV000271)#24176
twonky4 wants to merge 1 commit into
OpenAPITools:masterfrom
twonky4:fix/hv000271-java

Conversation

@twonky4

@twonky4 twonky4 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Fixes Hibernate Validator HV000271 ("Using @Valid on a container is deprecated. You should apply the annotation on the type argument(s)") across the Java generator family. HV 9.1+ (bundled with Spring Boot 4) logs this at WARN for every @Valid-annotated List/Set/Map — on both model properties and API parameters.

The fix relocates @Valid from the container to its type argument — the Bean-Validation-2.0 form (List<@Valid T>, Map<String, @Valid V>) — which cascades identically but is not deprecated. Backward-compatible: element validation is preserved, never dropped.

Scope (Java family): spring, java client, JAX-RS (jersey, resteasy(+eap), cxf(+extended/cdi), spec), java-camel.

  • Models (property/getter): the container @Valid is moved to the type argument. Map values are gated behind a new AbstractJavaCodegen#useBeanValidationOnMapValueType() (default false; overridden true in Spring/JavaClient/JAX-RS) so untouched generators don't silently gain map-value validation. Arrays/sets already injected the type-argument form.
  • Parameters (@RequestBody/@RequestParam/@RequestPart): the redundant container-level @Valid is dropped for container parameters; element validation is driven by the type-argument @Valid. Single-object parameters keep their @Valid. Reactive Mono/Flux bodies are intentionally untouched — they are not Jakarta containers and do not trigger HV000271.

The microprofile client bodyParams change is a consistency change with no sample impact (those samples don't enable bean validation).

Tests: added SpringCodegenTest#beanValidationOnContainerTypeArgument_issue23614 and #beanValidationOnContainerParameter_issue23614, JavaClientCodegenTest#testBeanValidationOnContainerTypeArgument_issue23614, updated JavaJAXRSSpecServerCodegenTest; the reactive test now also asserts the parameter-level @Valid is retained.

Fixes #23614

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    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.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Stops Hibernate Validator HV000271 by moving bean validation from containers to their type arguments without changing cascade behavior. Old: @Valid on List/Set/Map containers. New: List<@Valid T>, Map<String, @Valid V>. Single-object parameters stay @Valid; reactive Mono/Flux keep parameter-level @Valid.

  • Models: remove container-level @Valid; place it on array/set elements and composed-schema (oneOf/anyOf/allOf) elements except enums. Map values use type-argument validation gated by AbstractJavaCodegen#useBeanValidationOnMapValueType() (default false; overridden true in SpringCodegen, JavaClientCodegen, AbstractJavaJAXRSServerCodegen).
  • Parameters: drop container-level @Valid on @RequestBody, @RequestParam, @RequestPart for containers, and on Optional-wrapped scalars; keep for other non-containers. Reactive bodies retain parameter-level @Valid and add type-argument validation inside Mono/Flux.
  • Cascade still works when only the type argument carries @Valid, verified on Spring Boot 3.3 and 4.1.
  • Updated Java, JAX-RS, Spring, java-camel, and microprofile templates; added/updated tests and regenerated samples.

Written for commit 3bfada1. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 579 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/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/model/ArrayOfArrayOfNumberOnly.java">

<violation number="1" location="samples/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/model/ArrayOfArrayOfNumberOnly.java:50">
P3: Unused `jakarta.validation.Valid` import remains after the only `@Valid` annotation in the class was removed.</violation>
</file>

<file name="samples/client/petstore/java/rest-assured/src/main/java/org/openapitools/client/model/ArrayOfNumberOnly.java">

<violation number="1" location="samples/client/petstore/java/rest-assured/src/main/java/org/openapitools/client/model/ArrayOfNumberOnly.java:64">
P3: `javax.validation.Valid` import is unused after the only @Valid annotation was removed from the getter. This leaves stale generated code that can trigger lint/checkstyle failures.</violation>
</file>

Note: This PR contains a large number of files. cubic only reviews up to 200 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.

Re-trigger cubic

@@ -47,7 +47,7 @@ public ArrayOfArrayOfNumberOnly addArrayArrayNumberItem(List<BigDecimal> arrayAr
* Get arrayArrayNumber

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Unused jakarta.validation.Valid import remains after the only @Valid annotation in the class was removed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/server/petstore/springboot-implicitHeaders/src/main/java/org/openapitools/model/ArrayOfArrayOfNumberOnly.java, line 50:

<comment>Unused `jakarta.validation.Valid` import remains after the only `@Valid` annotation in the class was removed.</comment>

<file context>
@@ -47,7 +47,7 @@ public ArrayOfArrayOfNumberOnly addArrayArrayNumberItem(List<BigDecimal> arrayAr
    * @return arrayArrayNumber
    */
-  @Valid 
+  
   @Schema(name = "ArrayArrayNumber", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
   @JsonProperty("ArrayArrayNumber")
</file context>

*/
@javax.annotation.Nullable
@Valid

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: javax.validation.Valid import is unused after the only @Valid annotation was removed from the getter. This leaves stale generated code that can trigger lint/checkstyle failures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/java/rest-assured/src/main/java/org/openapitools/client/model/ArrayOfNumberOnly.java, line 64:

<comment>`javax.validation.Valid` import is unused after the only @Valid annotation was removed from the getter. This leaves stale generated code that can trigger lint/checkstyle failures.</comment>

<file context>
@@ -61,7 +61,6 @@ public ArrayOfNumberOnly addArrayNumberItem(BigDecimal arrayNumberItem) {
    */
   @javax.annotation.Nullable
-  @Valid
 
 
   public List<BigDecimal> getArrayNumber() {
</file context>

@twonky4
twonky4 force-pushed the fix/hv000271-java branch from 4691ca2 to fd351f8 Compare July 1, 2026 18:38
@twonky4

twonky4 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

A note to save reviewers some time.

On the automated review flagging that dropping the parameter-level @Valid disables element validation

It doesn't. The generated API interface is annotated @Validated, so Spring method validation cascades into a container parameter via the type-argument @Valid (List<@Valid T> / Map<String, @Valid V>) — the parameter-level container @Valid is redundant for that and only exists to trigger the HV000271 deprecation warning.

Verified empirically on Spring Boot 3.3 (Spring 6.1 / Hibernate Validator 8) and Spring Boot 4.1 (Spring 7 / Hibernate Validator 9.1), using an isolated single-method @Validated controller (no sibling @Valid, to rule out any bean-level effect):

@RestController
@Validated
class C {
    @PostMapping("/x")
    String x(@RequestBody List<@Valid Pet> body) { return "ok"; }   // Pet.name is @NotNull
}

Posting [{}] to /x:

  • new form @RequestBody List<@Valid Pet>ConstraintViolationException: x.body[0].name: must not be null (element validation runs), no HV000271
  • old form @Valid @RequestBody List<@Valid Pet> → same ConstraintViolationException, plus HV000271 on HV 9.1+

So element validation is preserved on both Spring versions; the change only removes the deprecation warning. Single-object body parameters keep their @Valid, and reactive Mono/Flux bodies are deliberately left untouched (they are not Jakarta containers and don't trigger HV000271).

@wing328

wing328 commented Jul 22, 2026

Copy link
Copy Markdown
Member

https://github.com/OpenAPITools/openapi-generator/actions/runs/28539637986/job/84609826940?pr=24176 should be fixed in the latest master

please merge the latest into your branch and resolve the merge conflicts when you've time

@twonky4

twonky4 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@wing328 rebased and conflicts solved.

@JFCote

JFCote commented Aug 19, 2026

Copy link
Copy Markdown
Member

@twonky4 @wing328 Do you guys need help to get this merged. I really need this in the next release and ready to help. I was coding my own fixe and was about to create a PR when I found this one.

@twonky4
twonky4 force-pushed the fix/hv000271-java branch from 81f2a3b to 0d1b1d1 Compare August 19, 2026 14:39
@twonky4

twonky4 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest master again and resolved the conflicts (only JavaSpring/beanValidation.mustache, due to the recent @NotNull→notNull partial refactor). All GitHub Actions checks are green, including "Samples up-to-date". The only red checks are the CircleCI node1 (Perl) and node2 (cpp-restsdk) shards, which are unrelated to this Java-only change — the PR touches no Perl/C++ files, and those shards run only Perl/C++ integration tests; looks like flaky infra, a re-run should clear them. Ready for review/merge. @JFCote thanks for the offer to help!

@JFCote

JFCote commented Aug 19, 2026

Copy link
Copy Markdown
Member

@twonky4 No problem! I checked your code and it was almost exactly what I had done + other awesome additions.
Let's wait for @wing328 to merge this.

@wing328 wing328 modified the milestones: 7.25.0, 7.26.0 Aug 24, 2026
@twonky4
twonky4 force-pushed the fix/hv000271-java branch 2 times, most recently from dd9af54 to ee93f53 Compare August 27, 2026 12:52

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 issues found across 597 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="modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParams.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParams.mustache:1">
P2: For `jaxrs-cxf-client` map body parameters, this guard removes the only `@Valid` because `JavaCXFClientCodegen` leaves map-value type annotations disabled. Override `useBeanValidationOnMapValueType()` in `JavaCXFClientCodegen` or retain container-level `@Valid` for this generator so map-value validation is not lost.</violation>
</file>

<file name="samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/model/ArrayTest.java">

<violation number="1" location="samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/model/ArrayTest.java:113">
P2: Dropping the container-level @Valid from the nested-container property getArrayArrayOfModel() (type List<List<@Valid ReadOnlyFirst>>) breaks cascaded element validation. In Bean Validation 2.0 a cascade must be declared at each container level, so validating the innermost ReadOnlyFirst elements requires List<@Valid List<@Valid ReadOnlyFirst>>. The current output has @Valid only on the innermost type argument, so the validator never descends into the inner Lists and the ReadOnlyFirst elements are no longer validated. This contradicts the PR's claim that element validation is preserved. The generator's getTypeDeclarationWithBeanValidation/getBeanValidation returns no annotation for the intermediate array type, so the fix must be in the generator: place @Valid on the intermediate container type argument (and regenerate the sample) when an array/set element is itself a container.</violation>
</file>

<file name="samples/client/petstore/java/jersey3-jackson3/src/main/java/org/openapitools/client/model/ArrayTest.java">

<violation number="1" location="samples/client/petstore/java/jersey3-jackson3/src/main/java/org/openapitools/client/model/ArrayTest.java:112">
P2: For the nested container `arrayArrayOfModel` (`List<List<@Valid ReadOnlyFirst>>`), removing the getter's `@Valid` drops element validation: the outer list is now neither getter-annotated nor type-argument-`@Valid`, so Bean Validation never cascades into the inner lists and the innermost `@Valid ReadOnlyFirst` is never reached. To preserve cascading HV000271-style, `@Valid` must appear on every nesting level, i.e. `List<@Valid List<@Valid ReadOnlyFirst>>`. The generator only annotates the deepest element type, so this regression hits all nested-container models in the migrated generators.</violation>
</file>

<file name="samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/UserApi.java">

<violation number="1" location="samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/UserApi.java:85">
P1: For a Spring @RequestBody, validation is triggered by @Valid/@Validated on the parameter itself: RequestResponseBodyMethodProcessor.validateIfApplicable scans only parameter.getParameterAnnotations() and never sees the type-use @Valid inside List<@Valid User>. Removing @Valid from the container therefore disables validation of the body entirely, so the list elements are not validated — contradicting the PR claim that element validation is preserved. Keep the parameter-level @Valid on @RequestBody (rely on the type-argument @Valid for the cascade) so Spring still validates the body.</violation>
</file>

<file name="samples/openapi3/client/petstore/spring-cloud-3-with-optional/src/main/java/org/openapitools/api/UserApi.java">

<violation number="1" location="samples/openapi3/client/petstore/spring-cloud-3-with-optional/src/main/java/org/openapitools/api/UserApi.java:58">
P1: Removing the parameter-level @Valid from `@RequestBody List<@Valid User>` disables body validation in Spring MVC. Spring only validates a @RequestBody when the parameter itself is annotated @Valid/@Validated; the type-argument @Valid on the element type is not a trigger and is never evaluated because binder.validate() is never called. The previous `@Valid @RequestBody List<@Valid User>` validated each element, so this change silently drops element validation for container request bodies (invalid elements now pass through). Keep the parameter @Valid (it is Spring's validation trigger, not the deprecated container-level @Valid) and retain the type-argument @Valid to fix HV000271: `@Valid @RequestBody List<@Valid User> user`.</violation>
</file>

<file name="samples/openapi3/client/petstore/spring-cloud/src/main/java/org/openapitools/api/UserApi.java">

<violation number="1" location="samples/openapi3/client/petstore/spring-cloud/src/main/java/org/openapitools/api/UserApi.java:95">
P1: Removing the parameter-level @Valid from a container @RequestBody disables Spring's automatic request-body validation. Spring's RequestResponseBodyMethodProcessor.validateIfApplicable only scans the parameter's declaration annotations (@Valid/@Validated) to decide whether to call binder.validate(); the @Valid on the List type argument is a type-use annotation that is never examined, so binder.validate() is never invoked and neither the container nor its elements get validated. This contradicts the PR's claim that element validation is preserved via the type-argument @Valid, and it affects every server-side method the shared JavaSpring bodyParams template generates (a list/map @RequestBody now silently skips validation).</violation>
</file>

<file name="samples/client/petstore/spring-cloud-tags/src/main/java/org/openapitools/api/UserController.java">

<violation number="1" location="samples/client/petstore/spring-cloud-tags/src/main/java/org/openapitools/api/UserController.java:85">
P2: Removing the parameter-level `@Valid` on `@RequestBody List<@Valid User>` disables Spring MVC's built-in request-body validation trigger (`RequestResponseBodyMethodProcessor` only acts on a parameter-declared `@Valid`/`@Validated`; it does not see the type-use `@Valid User`). Element validation now depends entirely on the `@Validated` method-validation AOP path, which requires `spring-boot-starter-validation` and a proxied controller whose interface `@Validated` is recognized. That path is present in the standard generated setup, but in any integration where method validation isn't active, the list body silently becomes fully unvalidated (no binding-validation fallback and no compile-time signal). Worth confirming/documenting this contract, e.g. by asserting in the generated server that `@Validated` + MethodValidationPostProcessor are actually in effect for container `@RequestBody`/`@RequestParam` params.</violation>
</file>

<file name="samples/openapi3/client/petstore/spring-stubs-skip-default-interface/src/main/java/org/openapitools/api/UserApi.java">

<violation number="1" location="samples/openapi3/client/petstore/spring-stubs-skip-default-interface/src/main/java/org/openapitools/api/UserApi.java:95">
P1: Removing the container-level @Valid leaves `@RequestBody List<@Valid User> user` with no validation trigger. Spring MVC only validates a @RequestBody when @Valid/@Validated is on the parameter itself; the type-use @Valid inside `List<@Valid User>` is a container element constraint processed during validation, not a trigger. On the standard data-binding path these list bodies are now deserialized without validating any User element, so element validation is not preserved as the PR claims. Keep a parameter-level validation trigger (for example `@Valid @RequestBody List<@Valid User>`) or verify via a runtime test that element validation still fires.</violation>
</file>

<file name="samples/openapi3/server/petstore/springboot/src/main/java/org/openapitools/api/UserApi.java">

<violation number="1" location="samples/openapi3/server/petstore/springboot/src/main/java/org/openapitools/api/UserApi.java:106">
P1: For container @RequestBody/@RequestParam/@RequestPart, removing the parameter-level @Valid leaves only the type-use `@Valid` inside `List<@Valid User>`. Spring MVC's RequestResponseBodyMethodProcessor decides whether to validate from the parameter itself (`@Valid`/`@Validated` on the parameter), not from a type-argument annotation, so element validation is silently dropped for every generated controller in the Spring family. Keep `@Valid` on the parameter and put the cascading `@Valid` on the type argument (as in `@Valid @RequestBody List<@Valid User>`); the parameter-level `@Valid` is distinct from a container-type annotation, so it does not reintroduce HV000271. Reactive params are unaffected since the template retains `@Valid` there.</violation>
</file>

<file name="samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/UserApi.java">

<violation number="1" location="samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/UserApi.java:89">
P1: Removing the container-level @Valid disables request-body validation in Spring MVC. Spring triggers body validation only when the method parameter itself is annotated with @Valid/@Validated (validateIfApplicable reads the parameter annotations); the class-level @Validated here does not apply to @RequestBody. So `@RequestBody List<@Valid User>` is never validated, and the type-argument @Valid on the elements is never evaluated either — the advertised backward-compatible element validation is lost. Keep @Valid on the container for request-body params: `@Valid @RequestBody List<@Valid User>`.</violation>
</file>

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Re-trigger cubic

)
ResponseEntity<Void> createUsersWithArrayInput(
@Parameter(name = "body", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> body
@Parameter(name = "body", description = "List of user object", required = true) @RequestBody List<@Valid User> body

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: For a Spring @RequestBody, validation is triggered by @Valid/@validated on the parameter itself: RequestResponseBodyMethodProcessor.validateIfApplicable scans only parameter.getParameterAnnotations() and never sees the type-use @Valid inside List<@Valid User>. Removing @Valid from the container therefore disables validation of the body entirely, so the list elements are not validated — contradicting the PR claim that element validation is preserved. Keep the parameter-level @Valid on @RequestBody (rely on the type-argument @Valid for the cascade) so Spring still validates the body.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/spring-cloud-spring-pageable/src/main/java/org/openapitools/api/UserApi.java, line 85:

<comment>For a Spring @RequestBody, validation is triggered by @Valid/@Validated on the parameter itself: RequestResponseBodyMethodProcessor.validateIfApplicable scans only parameter.getParameterAnnotations() and never sees the type-use @Valid inside List<@Valid User>. Removing @Valid from the container therefore disables validation of the body entirely, so the list elements are not validated — contradicting the PR claim that element validation is preserved. Keep the parameter-level @Valid on @RequestBody (rely on the type-argument @Valid for the cascade) so Spring still validates the body.</comment>

<file context>
@@ -82,7 +82,7 @@ ResponseEntity<Void> createUser(
     )
     ResponseEntity<Void> createUsersWithArrayInput(
-        @Parameter(name = "body", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> body
+        @Parameter(name = "body", description = "List of user object", required = true) @RequestBody List<@Valid User> body
     );
 
</file context>

)
ResponseEntity<Void> createUsersWithArrayInput(
@Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user
@Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Removing the container-level @Valid disables request-body validation in Spring MVC. Spring triggers body validation only when the method parameter itself is annotated with @Valid/@validated (validateIfApplicable reads the parameter annotations); the class-level @validated here does not apply to @RequestBody. So @RequestBody List<@Valid User> is never validated, and the type-argument @Valid on the elements is never evaluated either — the advertised backward-compatible element validation is lost. Keep @Valid on the container for request-body params: @Valid @RequestBody List<@Valid User>.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/spring-cloud-oas3-fakeapi/src/main/java/org/openapitools/api/UserApi.java, line 89:

<comment>Removing the container-level @Valid disables request-body validation in Spring MVC. Spring triggers body validation only when the method parameter itself is annotated with @Valid/@Validated (validateIfApplicable reads the parameter annotations); the class-level @Validated here does not apply to @RequestBody. So `@RequestBody List<@Valid User>` is never validated, and the type-argument @Valid on the elements is never evaluated either — the advertised backward-compatible element validation is lost. Keep @Valid on the container for request-body params: `@Valid @RequestBody List<@Valid User>`.</comment>

<file context>
@@ -86,7 +86,7 @@ ResponseEntity<Void> createUser(
     )
     ResponseEntity<Void> createUsersWithArrayInput(
-        @Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user
+        @Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user
     );
 
</file context>

)
ResponseEntity<Void> createUsersWithArrayInput(
@Valid @RequestBody List<@Valid User> user
@RequestBody List<@Valid User> user

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Removing the parameter-level @Valid from @RequestBody List<@Valid User> disables body validation in Spring MVC. Spring only validates a @RequestBody when the parameter itself is annotated @Valid/@validated; the type-argument @Valid on the element type is not a trigger and is never evaluated because binder.validate() is never called. The previous @Valid @RequestBody List<@Valid User> validated each element, so this change silently drops element validation for container request bodies (invalid elements now pass through). Keep the parameter @Valid (it is Spring's validation trigger, not the deprecated container-level @Valid) and retain the type-argument @Valid to fix HV000271: @Valid @RequestBody List<@Valid User> user.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/spring-cloud-3-with-optional/src/main/java/org/openapitools/api/UserApi.java, line 58:

<comment>Removing the parameter-level @Valid from `@RequestBody List<@Valid User>` disables body validation in Spring MVC. Spring only validates a @RequestBody when the parameter itself is annotated @Valid/@Validated; the type-argument @Valid on the element type is not a trigger and is never evaluated because binder.validate() is never called. The previous `@Valid @RequestBody List<@Valid User>` validated each element, so this change silently drops element validation for container request bodies (invalid elements now pass through). Keep the parameter @Valid (it is Spring's validation trigger, not the deprecated container-level @Valid) and retain the type-argument @Valid to fix HV000271: `@Valid @RequestBody List<@Valid User> user`.</comment>

<file context>
@@ -55,7 +55,7 @@ ResponseEntity<Void> createUser(
     )
     ResponseEntity<Void> createUsersWithArrayInput(
-         @Valid @RequestBody List<@Valid User> user
+         @RequestBody List<@Valid User> user
     );
 
</file context>
Suggested change
@RequestBody List<@Valid User> user
@Valid @RequestBody List<@Valid User> user

)
ResponseEntity<Void> createUsersWithArrayInput(
@Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user
@Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Removing the parameter-level @Valid from a container @RequestBody disables Spring's automatic request-body validation. Spring's RequestResponseBodyMethodProcessor.validateIfApplicable only scans the parameter's declaration annotations (@Valid/@validated) to decide whether to call binder.validate(); the @Valid on the List type argument is a type-use annotation that is never examined, so binder.validate() is never invoked and neither the container nor its elements get validated. This contradicts the PR's claim that element validation is preserved via the type-argument @Valid, and it affects every server-side method the shared JavaSpring bodyParams template generates (a list/map @RequestBody now silently skips validation).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/spring-cloud/src/main/java/org/openapitools/api/UserApi.java, line 95:

<comment>Removing the parameter-level @Valid from a container @RequestBody disables Spring's automatic request-body validation. Spring's RequestResponseBodyMethodProcessor.validateIfApplicable only scans the parameter's declaration annotations (@Valid/@Validated) to decide whether to call binder.validate(); the @Valid on the List type argument is a type-use annotation that is never examined, so binder.validate() is never invoked and neither the container nor its elements get validated. This contradicts the PR's claim that element validation is preserved via the type-argument @Valid, and it affects every server-side method the shared JavaSpring bodyParams template generates (a list/map @RequestBody now silently skips validation).</comment>

<file context>
@@ -92,7 +92,7 @@ ResponseEntity<Void> createUser(
     )
     ResponseEntity<Void> createUsersWithArrayInput(
-        @Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user
+        @Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user
     );
 
</file context>
Suggested change
@Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user
@Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user

)
ResponseEntity<Void> createUsersWithArrayInput(
@Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user
@Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Removing the container-level @Valid leaves @RequestBody List<@Valid User> user with no validation trigger. Spring MVC only validates a @RequestBody when @Valid/@validated is on the parameter itself; the type-use @Valid inside List<@Valid User> is a container element constraint processed during validation, not a trigger. On the standard data-binding path these list bodies are now deserialized without validating any User element, so element validation is not preserved as the PR claims. Keep a parameter-level validation trigger (for example @Valid @RequestBody List<@Valid User>) or verify via a runtime test that element validation still fires.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/spring-stubs-skip-default-interface/src/main/java/org/openapitools/api/UserApi.java, line 95:

<comment>Removing the container-level @Valid leaves `@RequestBody List<@Valid User> user` with no validation trigger. Spring MVC only validates a @RequestBody when @Valid/@Validated is on the parameter itself; the type-use @Valid inside `List<@Valid User>` is a container element constraint processed during validation, not a trigger. On the standard data-binding path these list bodies are now deserialized without validating any User element, so element validation is not preserved as the PR claims. Keep a parameter-level validation trigger (for example `@Valid @RequestBody List<@Valid User>`) or verify via a runtime test that element validation still fires.</comment>

<file context>
@@ -92,7 +92,7 @@ ResponseEntity<Void> createUser(
     )
     ResponseEntity<Void> createUsersWithArrayInput(
-        @Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user
+        @Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user
     ) throws Exception;
 
</file context>
Suggested change
@Parameter(name = "User", description = "List of user object", required = true) @RequestBody List<@Valid User> user
@Parameter(name = "User", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> user

* @return arrayArrayOfInteger
*/
@jakarta.annotation.Nullable
@Valid

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Dropping the container-level @Valid from the nested-container property getArrayArrayOfModel() (type List<List<@Valid ReadOnlyFirst>>) breaks cascaded element validation. In Bean Validation 2.0 a cascade must be declared at each container level, so validating the innermost ReadOnlyFirst elements requires List<@Valid List<@Valid ReadOnlyFirst>>. The current output has @Valid only on the innermost type argument, so the validator never descends into the inner Lists and the ReadOnlyFirst elements are no longer validated. This contradicts the PR's claim that element validation is preserved. The generator's getTypeDeclarationWithBeanValidation/getBeanValidation returns no annotation for the intermediate array type, so the fix must be in the generator: place @Valid on the intermediate container type argument (and regenerate the sample) when an array/set element is itself a container.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/model/ArrayTest.java, line 113:

<comment>Dropping the container-level @Valid from the nested-container property getArrayArrayOfModel() (type List<List<@Valid ReadOnlyFirst>>) breaks cascaded element validation. In Bean Validation 2.0 a cascade must be declared at each container level, so validating the innermost ReadOnlyFirst elements requires List<@Valid List<@Valid ReadOnlyFirst>>. The current output has @Valid only on the innermost type argument, so the validator never descends into the inner Lists and the ReadOnlyFirst elements are no longer validated. This contradicts the PR's claim that element validation is preserved. The generator's getTypeDeclarationWithBeanValidation/getBeanValidation returns no annotation for the intermediate array type, so the fix must be in the generator: place @Valid on the intermediate container type argument (and regenerate the sample) when an array/set element is itself a container.</comment>

<file context>
@@ -110,7 +110,6 @@ public ArrayTest addArrayArrayOfIntegerItem(List<Long> arrayArrayOfIntegerItem)
    */
   @jakarta.annotation.Nullable
-  @Valid
 
   @JsonProperty(value = JSON_PROPERTY_ARRAY_ARRAY_OF_INTEGER, required = false)
   @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
</file context>

* @return arrayArrayOfInteger
*/
@jakarta.annotation.Nullable
@Valid

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: For the nested container arrayArrayOfModel (List<List<@Valid ReadOnlyFirst>>), removing the getter's @Valid drops element validation: the outer list is now neither getter-annotated nor type-argument-@Valid, so Bean Validation never cascades into the inner lists and the innermost @Valid ReadOnlyFirst is never reached. To preserve cascading HV000271-style, @Valid must appear on every nesting level, i.e. List<@Valid List<@Valid ReadOnlyFirst>>. The generator only annotates the deepest element type, so this regression hits all nested-container models in the migrated generators.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/java/jersey3-jackson3/src/main/java/org/openapitools/client/model/ArrayTest.java, line 112:

<comment>For the nested container `arrayArrayOfModel` (`List<List<@Valid ReadOnlyFirst>>`), removing the getter's `@Valid` drops element validation: the outer list is now neither getter-annotated nor type-argument-`@Valid`, so Bean Validation never cascades into the inner lists and the innermost `@Valid ReadOnlyFirst` is never reached. To preserve cascading HV000271-style, `@Valid` must appear on every nesting level, i.e. `List<@Valid List<@Valid ReadOnlyFirst>>`. The generator only annotates the deepest element type, so this regression hits all nested-container models in the migrated generators.</comment>

<file context>
@@ -109,7 +109,6 @@ public ArrayTest addArrayArrayOfIntegerItem(List<Long> arrayArrayOfIntegerItem)
    */
   @jakarta.annotation.Nullable
-  @Valid
 
   @JsonProperty(value = JSON_PROPERTY_ARRAY_ARRAY_OF_INTEGER, required = false)
   @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
</file context>

)
ResponseEntity<Void> createUsersWithArrayInput(
@Parameter(name = "body", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> body
@Parameter(name = "body", description = "List of user object", required = true) @RequestBody List<@Valid User> body

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Removing the parameter-level @Valid on @RequestBody List<@Valid User> disables Spring MVC's built-in request-body validation trigger (RequestResponseBodyMethodProcessor only acts on a parameter-declared @Valid/@Validated; it does not see the type-use @Valid User). Element validation now depends entirely on the @Validated method-validation AOP path, which requires spring-boot-starter-validation and a proxied controller whose interface @Validated is recognized. That path is present in the standard generated setup, but in any integration where method validation isn't active, the list body silently becomes fully unvalidated (no binding-validation fallback and no compile-time signal). Worth confirming/documenting this contract, e.g. by asserting in the generated server that @Validated + MethodValidationPostProcessor are actually in effect for container @RequestBody/@RequestParam params.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/spring-cloud-tags/src/main/java/org/openapitools/api/UserController.java, line 85:

<comment>Removing the parameter-level `@Valid` on `@RequestBody List<@Valid User>` disables Spring MVC's built-in request-body validation trigger (`RequestResponseBodyMethodProcessor` only acts on a parameter-declared `@Valid`/`@Validated`; it does not see the type-use `@Valid User`). Element validation now depends entirely on the `@Validated` method-validation AOP path, which requires `spring-boot-starter-validation` and a proxied controller whose interface `@Validated` is recognized. That path is present in the standard generated setup, but in any integration where method validation isn't active, the list body silently becomes fully unvalidated (no binding-validation fallback and no compile-time signal). Worth confirming/documenting this contract, e.g. by asserting in the generated server that `@Validated` + MethodValidationPostProcessor are actually in effect for container `@RequestBody`/`@RequestParam` params.</comment>

<file context>
@@ -82,7 +82,7 @@ ResponseEntity<Void> createUser(
     )
     ResponseEntity<Void> createUsersWithArrayInput(
-        @Parameter(name = "body", description = "List of user object", required = true) @Valid @RequestBody List<@Valid User> body
+        @Parameter(name = "body", description = "List of user object", required = true) @RequestBody List<@Valid User> body
     );
 
</file context>

@twonky4
twonky4 force-pushed the fix/hv000271-java branch from ee93f53 to 36bf484 Compare August 28, 2026 06:56

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 597 files

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Re-trigger cubic

@twonky4
twonky4 force-pushed the fix/hv000271-java branch from 36bf484 to 3dbc3f6 Compare August 28, 2026 15:31

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 598 files

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Re-trigger cubic

…of the container (HV000271)

Hibernate Validator 9.1+ (bundled with Spring Boot 4) logs HV000271 ("Using
@Valid on a container is deprecated. You should apply the annotation on the
type argument(s)") for every @Valid-annotated List/Set/Map — on both model
properties and API parameters.

This relocates @Valid from the container to its type argument — the
Bean-Validation-2.0 form (List<@Valid T>, Map<String, @Valid V>) — which
cascades identically but is not deprecated. Backward-compatible: element
validation is preserved, never dropped; single-object @Valid is untouched.
Verified on Spring Boot 3.3 (Spring 6.1) and 4.1 (Spring 7): a container
parameter carrying only the type-argument @Valid still triggers element
validation via method validation, with no HV000271.

Scope (Java family): spring, java client, JAX-RS (jersey, resteasy(+eap),
cxf(+extended/cdi), spec), java-camel, java-msf4j.

Models (property/getter): the container @Valid is moved to the type argument.
Map values are gated behind a new
AbstractJavaCodegen#useBeanValidationOnMapValueType() (default false; overridden
true in Spring/JavaClient/JAX-RS) so untouched generators don't silently gain
map-value validation. Arrays/sets already injected the type-argument form.
oneOf/anyOf/allOf model elements now also receive the type-argument @Valid
(List<@Valid ShapeOneOf>), so their element validation is preserved rather than
dropped; a oneOf of constants (an enum) stays without @Valid.

Parameters (@RequestBody/@RequestParam/@RequestPart): the redundant
container-level @Valid is dropped for container parameters; element validation
is driven by the type-argument @Valid. Single-object parameters keep @Valid.
An Optional-wrapped scalar parameter (useOptional, e.g. Optional<Integer>) no
longer emits a parameter-level @Valid either — Hibernate Validator treats
Optional as a container, so it was the same HV000271 with nothing to cascade
into. Reactive Mono/Flux bodies are intentionally untouched (not Jakarta
containers, so no HV000271).

Regenerated all affected samples and added/updated codegen tests in
SpringCodegenTest, JavaClientCodegenTest, JavaJAXRSSpecServerCodegenTest and
JavaValidationArrayPrimitivesTest.
@twonky4
twonky4 force-pushed the fix/hv000271-java branch from 3dbc3f6 to 3bfada1 Compare August 28, 2026 19:03

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 599 files

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

Re-trigger cubic

@org.springframework.security.access.prepost.PreAuthorize("hasRole('ADMIN')")
ResponseEntity<List<Pet>> findPetsByStatus(
@NotNull @Parameter(name = "status", description = "Status values that need to be considered for filter", required = true, in = ParameterIn.QUERY) @Valid @RequestParam(value = "status", required = true) List<String> status,
@NotNull @Parameter(name = "status", description = "Status values that need to be considered for filter", required = true, in = ParameterIn.QUERY) @RequestParam(value = "status", required = true) List<String> status,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to:
https://docs.hibernate.org/validator/9.1/whats-new/en-US/html_single/#_deprecating_the_use_of_valid_at_the_container_level

Suggested change
@NotNull @Parameter(name = "status", description = "Status values that need to be considered for filter", required = true, in = ParameterIn.QUERY) @RequestParam(value = "status", required = true) List<String> status,
@NotNull @Parameter(name = "status", description = "Status values that need to be considered for filter", required = true, in = ParameterIn.QUERY) @RequestParam(value = "status", required = true) List<@Valid String> status,

Of course it may not a target for a String but it's important for an Object, in my case:
Before have

    ResponseEntity<ValuedAggregatedPositionReadDto> getAggregatedPosition(
        @NotNull @Size(min = 1)  @Valid @RequestParam(value = "accountIds", required = true) 
List<ShiftRawId> accountIds,

With this templates the @Valid is removed.

    ResponseEntity<ValuedAggregatedPositionReadDto> getAggregatedPosition(
        @NotNull @Size(min = 1)  @RequestParam(value = "accountIds", required = true) 
List<ShiftRawId> accountIds,

But I think we should have:

    ResponseEntity<ValuedAggregatedPositionReadDto> getAggregatedPosition(
        @NotNull @Size(min = 1)  @RequestParam(value = "accountIds", required = true) 
List<@Valid ShiftRawId> accountIds,

@pkernevez pkernevez Aug 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it My objects ShiftRawId are never validated.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right that a list of objects must keep element validation, and that's exactly what the PR does: List<@Valid X> for object models and, since a recent commit on this branch, also for oneOf/anyOf/allOf models.

If your ShiftRawId is a oneOf/composed type, that's the gap you hit: the deprecated container-level @Valid was dropped but the type-argument @Valid wasn't yet added for composed models. It is now. For example, a List<ShiftRawId> query parameter generates:

@NotNull @RequestParam(value = "accountIds", required = true) List<@Valid ShiftRawId> accountIds

Could you re-test on the latest commit? For List<String> (the status example in this hunk) there's intentionally no @Valid, since String isn't a cascade target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][JAVA] HV000271: Using @Valid on a container (java.util.List) is deprecated

4 participants