diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java index 6e68a74058..b95032d07f 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.validation.beanvalidation; import java.lang.reflect.Method; import java.util.Set; +import java.util.function.Supplier; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; @@ -35,6 +36,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.function.SingletonSupplier; import org.springframework.validation.annotation.Validated; /** @@ -60,14 +62,14 @@ import org.springframework.validation.annotation.Validated; */ public class MethodValidationInterceptor implements MethodInterceptor { - private final Validator validator; + private final Supplier validator; /** * Create a new MethodValidationInterceptor using a default JSR-303 validator underneath. */ public MethodValidationInterceptor() { - this(Validation.buildDefaultValidatorFactory()); + this.validator = SingletonSupplier.of(() -> Validation.buildDefaultValidatorFactory().getValidator()); } /** @@ -75,7 +77,7 @@ public class MethodValidationInterceptor implements MethodInterceptor { * @param validatorFactory the JSR-303 ValidatorFactory to use */ public MethodValidationInterceptor(ValidatorFactory validatorFactory) { - this(validatorFactory.getValidator()); + this.validator = SingletonSupplier.of(validatorFactory::getValidator); } /** @@ -83,6 +85,16 @@ public class MethodValidationInterceptor implements MethodInterceptor { * @param validator the JSR-303 Validator to use */ public MethodValidationInterceptor(Validator validator) { + this.validator = () -> validator; + } + + /** + * Create a new MethodValidationInterceptor for the supplied + * (potentially lazily initialized) Validator. + * @param validator a Supplier for the Validator to use + * @since 6.0 + */ + public MethodValidationInterceptor(Supplier validator) { this.validator = validator; } @@ -98,7 +110,7 @@ public class MethodValidationInterceptor implements MethodInterceptor { Class[] groups = determineValidationGroups(invocation); // Standard Bean Validation 1.1 API - ExecutableValidator execVal = this.validator.forExecutables(); + ExecutableValidator execVal = this.validator.get().forExecutables(); Method methodToValidate = invocation.getMethod(); Set> result; diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java index e24c9a0228..e0b14b865a 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,9 @@ package org.springframework.validation.beanvalidation; import java.lang.annotation.Annotation; +import java.util.function.Supplier; +import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.aopalliance.aop.Advice; @@ -27,9 +29,10 @@ import org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvis import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.function.SingletonSupplier; import org.springframework.validation.annotation.Validated; /** @@ -62,8 +65,8 @@ public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvis private Class validatedAnnotationType = Validated.class; - @Nullable - private Validator validator; + private Supplier validator = SingletonSupplier.of(() -> + Validation.buildDefaultValidatorFactory().getValidator()); /** @@ -79,31 +82,31 @@ public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvis this.validatedAnnotationType = validatedAnnotationType; } + /** + * Set the JSR-303 ValidatorFactory to delegate to for validating methods, + * using its default Validator. + *

Default is the default ValidatorFactory's default Validator. + * @see jakarta.validation.ValidatorFactory#getValidator() + */ + public void setValidatorFactory(ValidatorFactory validatorFactory) { + this.validator = SingletonSupplier.of(validatorFactory::getValidator); + } + /** * Set the JSR-303 Validator to delegate to for validating methods. *

Default is the default ValidatorFactory's default Validator. */ public void setValidator(Validator validator) { - // Unwrap to the native Validator with forExecutables support - if (validator instanceof LocalValidatorFactoryBean) { - this.validator = ((LocalValidatorFactoryBean) validator).getValidator(); - } - else if (validator instanceof SpringValidatorAdapter) { - this.validator = validator.unwrap(Validator.class); - } - else { - this.validator = validator; - } + this.validator = () -> validator; } /** - * Set the JSR-303 ValidatorFactory to delegate to for validating methods, - * using its default Validator. - *

Default is the default ValidatorFactory's default Validator. - * @see jakarta.validation.ValidatorFactory#getValidator() + * Set a lazily initialized Validator to delegate to for validating methods. + * @since 6.0 + * @see #setValidator */ - public void setValidatorFactory(ValidatorFactory validatorFactory) { - this.validator = validatorFactory.getValidator(); + public void setValidatorProvider(ObjectProvider validatorProvider) { + this.validator = validatorProvider::getObject; } @@ -116,13 +119,13 @@ public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvis /** * Create AOP advice for method validation purposes, to be applied * with a pointcut for the specified 'validated' annotation. - * @param validator the JSR-303 Validator to delegate to + * @param validator a Supplier for the Validator to use * @return the interceptor to use (typically, but not necessarily, * a {@link MethodValidationInterceptor} or subclass thereof) - * @since 4.2 + * @since 6.0 */ - protected Advice createMethodValidationAdvice(@Nullable Validator validator) { - return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor()); + protected Advice createMethodValidationAdvice(Supplier validator) { + return new MethodValidationInterceptor(validator); } }