Spring Framework 7.0.9, Hibernate Validator 9.1.3, Hibernate ORM 7.4.5, GraalVM 25.
BeanValidationBeanRegistrationAotProcessor only recurses into other types through Iterable, Optional and Map fields. A type validated through a plain @Valid field gets no reflection hints, and in a native image its constraints are not validated at all:
@Component
public class Example {
@Valid
@NotNull
private final Limits limits = new Limits(-1, -1);
record Limits(@Min(0) int timeToLiveSeconds, @Min(0) int maxSize) {
}
}
validator.validate(example);
On the JVM this reports two violations, limits.timeToLiveSeconds and limits.maxSize. In a native image it reports none, and so does validating a Limits instance directly.
If the nested type is registered for reflection for some other reason, e.g. only its constructor, its constraints are found, but its fields are still not registered, so validation then fails reading them. With Hibernate ORM on the class path:
org.graalvm.nativeimage.MissingReflectionRegistrationError: Cannot reflectively read or write field 'private final int example.Example$Limits.maxSize'
at org.hibernate.jpa.internal.util.PersistenceUtilHelper$FieldAttributeAccess.extractValue(PersistenceUtilHelper.java:257)
...
at org.hibernate.validator.internal.engine.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:49)
We ran into this with a record in Spring Boot configuration properties, for which Spring Boot registers the binding constructor.
A class whose only constraint is a @Valid field gets no hints either: without the @NotNull above, validation fails reading Example.limits.
Spring Framework 7.0.9, Hibernate Validator 9.1.3, Hibernate ORM 7.4.5, GraalVM 25.
BeanValidationBeanRegistrationAotProcessoronly recurses into other types throughIterable,OptionalandMapfields. A type validated through a plain@Validfield gets no reflection hints, and in a native image its constraints are not validated at all:On the JVM this reports two violations,
limits.timeToLiveSecondsandlimits.maxSize. In a native image it reports none, and so does validating aLimitsinstance directly.If the nested type is registered for reflection for some other reason, e.g. only its constructor, its constraints are found, but its fields are still not registered, so validation then fails reading them. With Hibernate ORM on the class path:
We ran into this with a record in Spring Boot configuration properties, for which Spring Boot registers the binding constructor.
A class whose only constraint is a
@Validfield gets no hints either: without the@NotNullabove, validation fails readingExample.limits.