Repository navigation
fix(java): place bean-validation @Valid on the type argument instead of the container (HV000271) #24176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(java): place bean-validation @Valid on the type argument instead of the container (HV000271) #24176
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -207,6 +207,14 @@ public DocumentationProvider defaultDocumentationProvider() { | |
| return DocumentationProvider.SOURCE; | ||
| } | ||
|
|
||
| @Override | ||
| protected boolean useBeanValidationOnMapValueType() { | ||
| // The Java templates place container element validation on the type argument | ||
| // (List<@Valid T>, Map<String, @Valid V>) rather than the deprecated | ||
| // container-level @Valid (HV000271). | ||
| return true; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: When a Java client enables Prompt for AI agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. This is not a regression introduced by this PR; the root cause is a pre-existing dependency pin rather than the The map-value change emits the same type-argument shape ( The pin you point at, Before this change, java-client map values carried no type-argument |
||
| } | ||
|
|
||
| @Override | ||
| public List<DocumentationProvider> supportedDocumentationProvider() { | ||
| List<DocumentationProvider> documentationProviders = new ArrayList<>(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}{{#useBeanValidation}}@Valid {{/useBeanValidation}}{{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDataType}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}{{#useBeanValidation}}{{^isContainer}}@Valid {{/isContainer}}{{/useBeanValidation}}{{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDataType}} {{paramName}}{{/isBodyParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#required}}{{^isReadOnly}}@NotNull {{/isReadOnly}}{{/required}}{{#isContainer}}{{^items.isPrimitiveType}}{{^items.isDate}}{{^items.isDateTime}}{{^items.isString}}{{^items.isFile}}{{^items.isEnumOrRef}}@Valid {{/items.isEnumOrRef}}{{/items.isFile}}{{/items.isString}}{{/items.isDateTime}}{{/items.isDate}}{{/items.isPrimitiveType}}{{/isContainer}}{{^isContainer}}{{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{^isEnumOrRef}}@Valid {{/isEnumOrRef}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}{{/isContainer}}{{>beanValidationCore}} | ||
| {{#required}}{{^isReadOnly}}@NotNull {{/isReadOnly}}{{/required}}{{^isContainer}}{{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{^isEnumOrRef}}@Valid {{/isEnumOrRef}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}{{/isContainer}}{{>beanValidationCore}} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Nested containers lose cascade validation because this branch removes the outer Prompt for AI agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nested containers keep cascade validation. The type-declaration builder recurses into the element type, so a |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}{{#useBeanValidation}}@Valid {{/useBeanValidation}}{{{dataType}}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}{{#useBeanValidation}}{{^isContainer}}@Valid {{/isContainer}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{/isBodyParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}{{#useBeanValidation}}@Valid {{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<InputStream>{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}{{#useBeanValidation}}{{^isContainer}}@Valid {{/isContainer}}{{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<InputStream>{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{/isBodyParam}} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: For Prompt for AI agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{.}}}"{{/defaultValue}}){{#useBeanValidation}}{{#required}} @NotNull{{/required}} @Valid{{/useBeanValidation}} {{{dataType}}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{.}}}"{{/defaultValue}}){{#useBeanValidation}}{{#required}} @NotNull{{/required}}{{^isContainer}} @Valid{{/isContainer}}{{/useBeanValidation}} {{{dataType}}} {{paramName}}{{/isBodyParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{.}}}"{{/defaultValue}}){{#useBeanValidation}}{{#required}} @NotNull{{/required}} @Valid{{/useBeanValidation}} {{{dataType}}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{.}}}"{{/defaultValue}}){{#useBeanValidation}}{{#required}} @NotNull{{/required}}{{^isContainer}} @Valid{{/isContainer}}{{/useBeanValidation}} {{{dataType}}} {{paramName}}{{/isBodyParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#required}}{{^isReadOnly}}@NotNull {{/isReadOnly}}{{/required}}{{#isContainer}}{{^items.isPrimitiveType}}{{^items.isDate}}{{^items.isDateTime}}{{^items.isString}}{{^items.isFile}}{{^items.isEnumOrRef}}@Valid {{/items.isEnumOrRef}}{{/items.isFile}}{{/items.isString}}{{/items.isDateTime}}{{/items.isDate}}{{/items.isPrimitiveType}}{{/isContainer}}{{^isContainer}}{{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{^isEnumOrRef}}@Valid {{/isEnumOrRef}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}{{/isContainer}}{{>beanValidationCore}} | ||
| {{#required}}{{^isReadOnly}}@NotNull {{/isReadOnly}}{{/required}}{{^isContainer}}{{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{^isEnumOrRef}}@Valid {{/isEnumOrRef}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}{{/isContainer}}{{>beanValidationCore}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}{{#isDeprecated}}@Deprecated {{/isDeprecated}}{{#useBeanValidation}}@Valid {{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDataType}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}{{#isDeprecated}}@Deprecated {{/isDeprecated}}{{#useBeanValidation}}{{^isContainer}}@Valid {{/isContainer}}{{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{#useJspecify}}{{>nullable_var_annotations}}{{/useJspecify}}{{>nullableDataType}} {{paramName}}{{/isBodyParam}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{>notNull}}{{#isContainer}}{{^isPrimitiveType}}{{^isEnum}}@Valid {{/isEnum}}{{/isPrimitiveType}}{{/isContainer}}{{^isContainer}}{{^isPrimitiveType}}@Valid {{/isPrimitiveType}}{{/isContainer}}{{^openApiNullable}}{{>beanValidationCore}}{{/openApiNullable}}{{#openApiNullable}}{{^useOptional}}{{>beanValidationCore}}{{/useOptional}}{{/openApiNullable}}{{#useOptional}}{{#openApiNullable}}{{#isContainer}}{{^required}}{{>beanValidationCore}}{{/required}}{{/isContainer}}{{/openApiNullable}}{{#openApiNullable}}{{#required}}{{>beanValidationCore}}{{/required}}{{/openApiNullable}}{{/useOptional}} | ||
| {{>notNull}}{{^isContainer}}{{^isPrimitiveType}}@Valid {{/isPrimitiveType}}{{/isContainer}}{{^openApiNullable}}{{>beanValidationCore}}{{/openApiNullable}}{{#openApiNullable}}{{^useOptional}}{{>beanValidationCore}}{{/useOptional}}{{/openApiNullable}}{{#useOptional}}{{#openApiNullable}}{{#isContainer}}{{^required}}{{>beanValidationCore}}{{/required}}{{/isContainer}}{{/openApiNullable}}{{#openApiNullable}}{{#required}}{{>beanValidationCore}}{{/required}}{{/openApiNullable}}{{/useOptional}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {{#isBodyParam}}{{>paramDoc}}{{#useBeanValidation}} {{>beanValidationBodyParams}}@Valid{{/useBeanValidation}} @RequestBody{{^required}}(required = false){{/required}} {{^reactive}}{{>nullableAnnotation}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isBodyParam}} | ||
| {{#isBodyParam}}{{>paramDoc}}{{#useBeanValidation}} {{>beanValidationBodyParams}}{{#reactive}}@Valid {{/reactive}}{{^reactive}}{{^isContainer}}@Valid {{/isContainer}}{{/reactive}}{{/useBeanValidation}}{{^useBeanValidation}} {{/useBeanValidation}}@RequestBody{{^required}}(required = false){{/required}} {{^reactive}}{{>nullableAnnotation}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isBodyParam}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: When a referenced composed schema has no
specVersion, this new condition callsisOneOfOfConsts, which dereferences that nullable value and aborts generation. Guard the version before calling the helper, or make the helper null-safe.Prompt for AI agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a real risk.
isOneOfOfConstsis a pre-existing ModelUtils helper already invoked byOpenAPINormalizeron every generation, andgetSpecVersion()is never null: swagger-models defaults the field toSpecVersion.V30. The&&short-circuits onhasOneOf(schema)beforegetSpecVersion()is reached, and for a missing refisComposedSchema(schema)returns false (null-safe) beforeisOneOfOfConstsis ever called. No nullable value is dereferenced.