Repository navigation
[BUG][KOTLIN-SPRING] @field:Valid on container properties triggers HV000271/HV000272 warnings (Hibernate Validator 9.1) #25347
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
Description
With useBeanValidation (default for kotlin-spring), beanValidation.mustache puts @field:Valid on container properties (List, Set, Map) and on free-form kotlin.Any properties.
Hibernate Validator 9.1 (shipped with Spring Boot 4.1) deprecated container-level @Valid and logs a warning while building bean metadata:
WARN org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder - HV000271: Using `@Valid` on a container (java.util.List) is deprecated. You should apply the annotation on the type argument(s). Affected element: items
WARN org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder - HV000272: Using `@Valid` on a container is deprecated. You should apply the annotation on the type argument(s). (java.lang.Object) can potentially be a container at runtime. Affected element: customInfo
Because the bean metadata cache in Hibernate Validator uses soft references, the warnings are not logged only once at startup - they are repeated each time the metadata of a rarely used model is evicted and rebuilt, which produces a steady stream of warnings in production logs.
The same problem was fixed for the Java generators in #24176 (released in 7.26.0, issue #23614) by moving @Valid to the type argument. The kotlin-spring templates were not touched. An attempt for Kotlin (#24027 / #24029) only removed @field:Valid from Map properties and was closed, because that silently drops cascading validation of the values.
Actual output
data class Pet(
@field:Valid
@get:JsonProperty("items") val items: kotlin.collections.List<Item>? = null,
@field:Valid
@get:JsonProperty("itemsByKey") val itemsByKey: kotlin.collections.Map<kotlin.String, Item>? = null,
@field:Valid
@get:JsonProperty("customInfo") val customInfo: kotlin.Any? = null
)Expected output
data class Pet(
@get:JsonProperty("items") val items: kotlin.collections.List<@Valid Item>? = null,
@get:JsonProperty("itemsByKey") val itemsByKey: kotlin.collections.Map<kotlin.String, @Valid Item>? = null,
@get:JsonProperty("customInfo") val customInfo: kotlin.Any? = null
)Important note for Kotlin: the Kotlin compiler does not write type-use annotations into the bytecode by default, so List<@Valid Item> alone is invisible to Hibernate Validator (cascading would silently stop working). It works only when the models are compiled with -Xemit-jvm-type-annotations (verified with Kotlin 2.3.21: without the flag there is no RuntimeVisibleTypeAnnotations attribute, with it cascading into list elements and map values works and no HV000271 is logged). The generator should therefore at least document this flag, or add it to the generated build.gradle.kts / pom.xml when useBeanValidation is enabled.
openapi-generator version
7.17.0 (the relevant kotlin-spring templates are unchanged in 7.26.0). Not a regression in the generator - it surfaced with Hibernate Validator 9.1.0.Final.
OpenAPI declaration file content or url
openapi: 3.0.3
info:
title: valid-on-container
version: 1.0.0
paths: {}
components:
schemas:
Pet:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/Item'
itemsByKey:
type: object
additionalProperties:
$ref: '#/components/schemas/Item'
customInfo:
type: object
Item:
type: object
required:
- name
properties:
name:
type: string
minLength: 1Generation Details
Gradle plugin org.openapi.generator 7.17.0:
openApiGenerate {
generatorName.set("kotlin-spring")
configOptions.put("useSpringBoot3", "true")
configOptions.put("interfaceOnly", "true")
}Steps to reproduce
- Generate the models from the spec above with
kotlin-spring. - Validate a
Petinstance with Hibernate Validator 9.1 (e.g.Validation.buildDefaultValidatorFactory().validator.validate(Pet(items = listOf(Item(name = ""))))). - HV000271 (for
items,itemsByKey) and HV000272 (forcustomInfo) warnings are logged.
Related issues/PRs
- [BUG][JAVA] HV000271: Using
@Validon a container (java.util.List) is deprecated #23614, fix(java): place bean-validation @Valid on the type argument instead of the container (HV000271) #24176 - same problem fixed for the Java generators - fix(kotlin-spring): skip @field:Valid on Map container properties (HV000271) #24027, fix(kotlin-spring): skip @field:Valid on Map container properties (HV000271) #24029 - closed Kotlin attempt (dropping
@Validfrom maps) - [Bug][Java/Spring] Container-level @Valid on Optional/JsonNullable-wrapped model properties triggers HV000271 (follow-up to #24176) #25097, [BUG][JAVA][SPRING] HV000271 still logged for non-required
@RequestBody Optional<Dto>(7.26.0) #25249 - remaining HV000271 cases in Java/Spring
Suggest a fix
In kotlin-spring (beanValidation.mustache + dataClassReqVar.mustache / dataClassOptVar.mustache, and the interface var templates):
- do not emit
@field:Validfor containers; render the type asList<@Valid T>/Set<@Valid T>/Map<String, @Valid V>instead, - do not emit
@field:Validfor free-formkotlin.Anyproperties, - document (or emit into the generated build file) the
-Xemit-jvm-type-annotationscompiler option required for the type-use annotations to be visible at runtime.
As a workaround we currently post-process the generated sources after openApiGenerate (moving @field:Valid to the type argument with a regex) and compile the models with -Xemit-jvm-type-annotations.
Activity