Lazy Validator resolution in MethodValidationPostProcessor
Closes gh-28990
This commit is contained in:
@@ -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> 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> 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<ConstraintViolation<Object>> result;
|
||||
|
||||
|
||||
@@ -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<? extends Annotation> validatedAnnotationType = Validated.class;
|
||||
|
||||
@Nullable
|
||||
private Validator validator;
|
||||
private Supplier<Validator> validator = SingletonSupplier.of(() ->
|
||||
Validation.buildDefaultValidatorFactory().getValidator());
|
||||
|
||||
|
||||
/**
|
||||
@@ -79,23 +82,6 @@ public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvis
|
||||
this.validatedAnnotationType = validatedAnnotationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSR-303 Validator to delegate to for validating methods.
|
||||
* <p>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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSR-303 ValidatorFactory to delegate to for validating methods,
|
||||
* using its default Validator.
|
||||
@@ -103,7 +89,24 @@ public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvis
|
||||
* @see jakarta.validation.ValidatorFactory#getValidator()
|
||||
*/
|
||||
public void setValidatorFactory(ValidatorFactory validatorFactory) {
|
||||
this.validator = validatorFactory.getValidator();
|
||||
this.validator = SingletonSupplier.of(validatorFactory::getValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSR-303 Validator to delegate to for validating methods.
|
||||
* <p>Default is the default ValidatorFactory's default Validator.
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = () -> validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a lazily initialized Validator to delegate to for validating methods.
|
||||
* @since 6.0
|
||||
* @see #setValidator
|
||||
*/
|
||||
public void setValidatorProvider(ObjectProvider<Validator> 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> validator) {
|
||||
return new MethodValidationInterceptor(validator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user