Skip to content

Commit f12dcb5

Browse files
committed
Merge pull request #29429 from dangzhicairang
* gh-29429: Polish "Provide callback mechanism for customizing validation configuration" Provide callback mechanism for customizing validation configuration Closes gh-29429
2 parents f3aa5d0 + 0e00faf commit f12dcb5

File tree

4 files changed

+78
-1
lines changed

4 files changed

+78
-1
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ public class ValidationAutoConfiguration {
5656
@Bean
5757
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
5858
@ConditionalOnMissingBean(Validator.class)
59-
public static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext) {
59+
public static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext,
60+
ObjectProvider<ValidationConfigurationCustomizer> customizers) {
6061
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
62+
factoryBean.setConfigurationInitializer((configuration) -> customizers.orderedStream()
63+
.forEach((customizer) -> customizer.customize(configuration)));
6164
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(applicationContext);
6265
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
6366
return factoryBean;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.validation;
18+
19+
import jakarta.validation.Configuration;
20+
21+
/**
22+
* Callback interface that can be used to customize {@link Configuration}.
23+
*
24+
* @author Dang Zhicairang
25+
* @since 3.0.0
26+
*/
27+
@FunctionalInterface
28+
public interface ValidationConfigurationCustomizer {
29+
30+
/**
31+
* Customize the given {@code configuration}.
32+
* @param configuration the configuration to customize
33+
*/
34+
void customize(Configuration<?> configuration);
35+
36+
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java

+35
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import jakarta.validation.constraints.Min;
2525
import jakarta.validation.constraints.Size;
2626
import org.junit.jupiter.api.Test;
27+
import org.mockito.InOrder;
28+
import org.mockito.Mockito;
2729

2830
import org.springframework.beans.factory.BeanFactoryUtils;
2931
import org.springframework.beans.factory.config.BeanPostProcessor;
@@ -36,6 +38,7 @@
3638
import org.springframework.context.annotation.Bean;
3739
import org.springframework.context.annotation.Configuration;
3840
import org.springframework.context.annotation.Primary;
41+
import org.springframework.core.annotation.Order;
3942
import org.springframework.test.util.ReflectionTestUtils;
4043
import org.springframework.validation.annotation.Validated;
4144
import org.springframework.validation.beanvalidation.CustomValidatorBean;
@@ -46,6 +49,8 @@
4649
import static org.assertj.core.api.Assertions.assertThat;
4750
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
4851
import static org.assertj.core.api.Assertions.assertThatNoException;
52+
import static org.mockito.ArgumentMatchers.any;
53+
import static org.mockito.BDDMockito.then;
4954
import static org.mockito.Mockito.mock;
5055

5156
/**
@@ -235,6 +240,19 @@ void validationIsEnabledInChildContext() {
235240
}));
236241
}
237242

243+
@Test
244+
void configurationCustomizerBeansAreCalledInOrder() {
245+
this.contextRunner.withUserConfiguration(ConfigurationCustomizersConfiguration.class).run((context) -> {
246+
ValidationConfigurationCustomizer customizerOne = context.getBean("customizerOne",
247+
ValidationConfigurationCustomizer.class);
248+
ValidationConfigurationCustomizer customizerTwo = context.getBean("customizerTwo",
249+
ValidationConfigurationCustomizer.class);
250+
InOrder inOrder = Mockito.inOrder(customizerOne, customizerTwo);
251+
then(customizerTwo).should(inOrder).customize(any(jakarta.validation.Configuration.class));
252+
then(customizerOne).should(inOrder).customize(any(jakarta.validation.Configuration.class));
253+
});
254+
}
255+
238256
private boolean isPrimaryBean(AssertableApplicationContext context, String beanName) {
239257
return ((BeanDefinitionRegistry) context.getSourceApplicationContext()).getBeanDefinition(beanName).isPrimary();
240258
}
@@ -421,4 +439,21 @@ public Object postProcessBeforeInitialization(Object bean, String name) {
421439

422440
}
423441

442+
@Configuration(proxyBeanMethods = false)
443+
static class ConfigurationCustomizersConfiguration {
444+
445+
@Bean
446+
@Order(1)
447+
ValidationConfigurationCustomizer customizerOne() {
448+
return mock(ValidationConfigurationCustomizer.class);
449+
}
450+
451+
@Bean
452+
@Order(0)
453+
ValidationConfigurationCustomizer customizerTwo() {
454+
return mock(ValidationConfigurationCustomizer.class);
455+
}
456+
457+
}
458+
424459
}

spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/validation.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ include::code:MyBean[]
1111
The application's `MessageSource` is used when resolving `+{parameters}+` in constraint messages.
1212
This allows you to use <<features.adoc#features.internationalization,your application's `messages.properties` files>> for Bean Validation messages.
1313
Once the parameters have been resolved, message interpolation is completed using Bean Validation's default interpolator.
14+
15+
To customize the `Configuration` used to build the `ValidatorFactory`, define a `ValidationConfigurationCustomizer` bean.
16+
When multiple customizer beans are defined, they are called in order based on their `@Order` annotation or `Ordered` implementation.

0 commit comments

Comments
 (0)