Skip to content

Commit 0e00faf

Browse files
committed
Polish "Provide callback mechanism for customizing validation configuration"
See gh-29429
1 parent 76a1c6b commit 0e00faf

File tree

6 files changed

+50
-134
lines changed

6 files changed

+50
-134
lines changed

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

+4-16
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@
1616

1717
package org.springframework.boot.autoconfigure.validation;
1818

19-
import java.util.List;
20-
2119
import jakarta.validation.Validator;
2220
import jakarta.validation.executable.ExecutableValidator;
23-
import jakarta.validation.valueextraction.ValueExtractor;
2421

2522
import org.springframework.beans.factory.ObjectProvider;
2623
import org.springframework.beans.factory.config.BeanDefinition;
@@ -31,11 +28,8 @@
3128
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
3229
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
3330
import org.springframework.boot.validation.MessageInterpolatorFactory;
34-
import org.springframework.boot.validation.beanvalidation.CustomizableLocalValidatorFactoryBean;
3531
import org.springframework.boot.validation.beanvalidation.FilteredMethodValidationPostProcessor;
3632
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
37-
import org.springframework.boot.validation.beanvalidation.customize.AddValueExtractorCustomizer;
38-
import org.springframework.boot.validation.beanvalidation.customize.Customizer;
3933
import org.springframework.context.ApplicationContext;
4034
import org.springframework.context.annotation.Bean;
4135
import org.springframework.context.annotation.Import;
@@ -59,20 +53,14 @@
5953
@Import(PrimaryDefaultValidatorPostProcessor.class)
6054
public class ValidationAutoConfiguration {
6155

62-
@Bean
63-
public static AddValueExtractorCustomizer autoAddValueExtractorCustomizer(
64-
@SuppressWarnings({ "rawtypes", "unchecked" }) List<ValueExtractor> valueExtractors) {
65-
66-
return new AddValueExtractorCustomizer(valueExtractors);
67-
}
68-
6956
@Bean
7057
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
7158
@ConditionalOnMissingBean(Validator.class)
7259
public static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext,
73-
List<Customizer> customizers) {
74-
CustomizableLocalValidatorFactoryBean factoryBean = new CustomizableLocalValidatorFactoryBean();
75-
factoryBean.setCustomizers(customizers);
60+
ObjectProvider<ValidationConfigurationCustomizer> customizers) {
61+
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
62+
factoryBean.setConfigurationInitializer((configuration) -> customizers.orderedStream()
63+
.forEach((customizer) -> customizer.customize(configuration)));
7664
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(applicationContext);
7765
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
7866
return factoryBean;

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/validation/beanvalidation/customize/Customizer.java renamed to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationConfigurationCustomizer.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,20 +14,23 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.validation.beanvalidation.customize;
17+
package org.springframework.boot.autoconfigure.validation;
1818

1919
import jakarta.validation.Configuration;
2020

2121
/**
2222
* Callback interface that can be used to customize {@link Configuration}.
2323
*
2424
* @author Dang Zhicairang
25-
* @since 2.6.2
26-
* @see AddValueExtractorCustomizer
25+
* @since 3.0.0
2726
*/
2827
@FunctionalInterface
29-
public interface Customizer {
28+
public interface ValidationConfigurationCustomizer {
3029

30+
/**
31+
* Customize the given {@code configuration}.
32+
* @param configuration the configuration to customize
33+
*/
3134
void customize(Configuration<?> configuration);
3235

3336
}

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.

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/validation/beanvalidation/CustomizableLocalValidatorFactoryBean.java

-59
This file was deleted.

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/validation/beanvalidation/customize/AddValueExtractorCustomizer.java

-54
This file was deleted.

0 commit comments

Comments
 (0)