Polish "Provide callback mechanism for customizing validation configuration"
See gh-29429
This commit is contained in:
parent
76a1c6bcaa
commit
0e00fafe38
|
@ -16,11 +16,8 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.validation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.executable.ExecutableValidator;
|
||||
import jakarta.validation.valueextraction.ValueExtractor;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
@ -31,11 +28,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.boot.validation.beanvalidation.CustomizableLocalValidatorFactoryBean;
|
||||
import org.springframework.boot.validation.beanvalidation.FilteredMethodValidationPostProcessor;
|
||||
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
|
||||
import org.springframework.boot.validation.beanvalidation.customize.AddValueExtractorCustomizer;
|
||||
import org.springframework.boot.validation.beanvalidation.customize.Customizer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
@ -59,20 +53,14 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
|||
@Import(PrimaryDefaultValidatorPostProcessor.class)
|
||||
public class ValidationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public static AddValueExtractorCustomizer autoAddValueExtractorCustomizer(
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) List<ValueExtractor> valueExtractors) {
|
||||
|
||||
return new AddValueExtractorCustomizer(valueExtractors);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@ConditionalOnMissingBean(Validator.class)
|
||||
public static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext,
|
||||
List<Customizer> customizers) {
|
||||
CustomizableLocalValidatorFactoryBean factoryBean = new CustomizableLocalValidatorFactoryBean();
|
||||
factoryBean.setCustomizers(customizers);
|
||||
ObjectProvider<ValidationConfigurationCustomizer> customizers) {
|
||||
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
|
||||
factoryBean.setConfigurationInitializer((configuration) -> customizers.orderedStream()
|
||||
.forEach((customizer) -> customizer.customize(configuration)));
|
||||
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(applicationContext);
|
||||
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
|
||||
return factoryBean;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-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.
|
||||
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.validation.beanvalidation.customize;
|
||||
package org.springframework.boot.autoconfigure.validation;
|
||||
|
||||
import jakarta.validation.Configuration;
|
||||
|
||||
|
@ -22,12 +22,15 @@ import jakarta.validation.Configuration;
|
|||
* Callback interface that can be used to customize {@link Configuration}.
|
||||
*
|
||||
* @author Dang Zhicairang
|
||||
* @since 2.6.2
|
||||
* @see AddValueExtractorCustomizer
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Customizer {
|
||||
public interface ValidationConfigurationCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the given {@code configuration}.
|
||||
* @param configuration the configuration to customize
|
||||
*/
|
||||
void customize(Configuration<?> configuration);
|
||||
|
||||
}
|
|
@ -24,6 +24,8 @@ import jakarta.validation.Validator;
|
|||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
@ -36,6 +38,7 @@ import org.springframework.boot.validation.beanvalidation.MethodValidationExclud
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.beanvalidation.CustomValidatorBean;
|
||||
|
@ -46,6 +49,8 @@ import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBea
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
|
@ -235,6 +240,19 @@ class ValidationAutoConfigurationTests {
|
|||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationCustomizerBeansAreCalledInOrder() {
|
||||
this.contextRunner.withUserConfiguration(ConfigurationCustomizersConfiguration.class).run((context) -> {
|
||||
ValidationConfigurationCustomizer customizerOne = context.getBean("customizerOne",
|
||||
ValidationConfigurationCustomizer.class);
|
||||
ValidationConfigurationCustomizer customizerTwo = context.getBean("customizerTwo",
|
||||
ValidationConfigurationCustomizer.class);
|
||||
InOrder inOrder = Mockito.inOrder(customizerOne, customizerTwo);
|
||||
then(customizerTwo).should(inOrder).customize(any(jakarta.validation.Configuration.class));
|
||||
then(customizerOne).should(inOrder).customize(any(jakarta.validation.Configuration.class));
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isPrimaryBean(AssertableApplicationContext context, String beanName) {
|
||||
return ((BeanDefinitionRegistry) context.getSourceApplicationContext()).getBeanDefinition(beanName).isPrimary();
|
||||
}
|
||||
|
@ -421,4 +439,21 @@ class ValidationAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ConfigurationCustomizersConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
ValidationConfigurationCustomizer customizerOne() {
|
||||
return mock(ValidationConfigurationCustomizer.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
ValidationConfigurationCustomizer customizerTwo() {
|
||||
return mock(ValidationConfigurationCustomizer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,3 +11,6 @@ include::code:MyBean[]
|
|||
The application's `MessageSource` is used when resolving `+{parameters}+` in constraint messages.
|
||||
This allows you to use <<features.adoc#features.internationalization,your application's `messages.properties` files>> for Bean Validation messages.
|
||||
Once the parameters have been resolved, message interpolation is completed using Bean Validation's default interpolator.
|
||||
|
||||
To customize the `Configuration` used to build the `ValidatorFactory`, define a `ValidationConfigurationCustomizer` bean.
|
||||
When multiple customizer beans are defined, they are called in order based on their `@Order` annotation or `Ordered` implementation.
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2020 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.validation.beanvalidation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.validation.Configuration;
|
||||
|
||||
import org.springframework.boot.validation.beanvalidation.customize.Customizer;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
/**
|
||||
* This class will callback the {@link Customizer} which supply by application. For
|
||||
* example:
|
||||
*
|
||||
* <pre>{@code
|
||||
* @Bean
|
||||
* public Customizer customizer() {
|
||||
* return configuration -> {
|
||||
* configuration.addValueExtractor(new CustomResultValueExtractor());
|
||||
* configuration.xxx
|
||||
* ...
|
||||
* };
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @author Dang Zhicairang
|
||||
* @since 2.6.2
|
||||
*/
|
||||
public class CustomizableLocalValidatorFactoryBean extends LocalValidatorFactoryBean {
|
||||
|
||||
private List<Customizer> customizers;
|
||||
|
||||
public void setCustomizers(List<Customizer> customizers) {
|
||||
this.customizers = customizers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcessConfiguration(Configuration<?> configuration) {
|
||||
Optional.ofNullable(this.customizers)
|
||||
.ifPresent((list) -> list.forEach((customizer) -> customizer.customize(configuration)));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2020 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.validation.beanvalidation.customize;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.validation.Configuration;
|
||||
import jakarta.validation.valueextraction.ValueExtractor;
|
||||
|
||||
/**
|
||||
* Add given collection of {@link ValueExtractor} into {@link Configuration}.
|
||||
*
|
||||
* @author Dang Zhicairang
|
||||
* @since 2.6.2
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class AddValueExtractorCustomizer implements Customizer {
|
||||
|
||||
private List<ValueExtractor> valueExtractors;
|
||||
|
||||
public AddValueExtractorCustomizer(List<ValueExtractor> valueExtractors) {
|
||||
this.valueExtractors = valueExtractors;
|
||||
}
|
||||
|
||||
public List<ValueExtractor> getValueExtractors() {
|
||||
return this.valueExtractors;
|
||||
}
|
||||
|
||||
public void setValueExtractors(List<ValueExtractor> valueExtractors) {
|
||||
this.valueExtractors = valueExtractors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(Configuration<?> configuration) {
|
||||
Optional.ofNullable(this.getValueExtractors())
|
||||
.ifPresent((list) -> list.forEach(configuration::addValueExtractor));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue