Exclude property beans from method validation
Exclude `@ConfigurationProperties` beans from method validation so that `@Validated` can be used on final classes without the method validation post-processor throwing an exception. This commit introduces a `FilteredMethodValidationPostProcessor` class which will use `MethodValidationExcludeFilters` to exclude beans from method validation processing. Using `@EnableConfigurationProperties` will automatically register an appropriate filter. Closes gh-21454
This commit is contained in:
committed by
Phillip Webb
parent
a0862f9146
commit
f60f3cb38e
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -19,12 +19,15 @@ package org.springframework.boot.autoconfigure.validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.executable.ExecutableValidator;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.boot.validation.beanvalidation.FilteredMethodValidationPostProcessor;
|
||||
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
@@ -61,8 +64,9 @@ public class ValidationAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
|
||||
@Lazy Validator validator) {
|
||||
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
|
||||
@Lazy Validator validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {
|
||||
FilteredMethodValidationPostProcessor processor = new FilteredMethodValidationPostProcessor(
|
||||
excludeFilters.orderedStream());
|
||||
boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
|
||||
processor.setProxyTargetClass(proxyTargetClass);
|
||||
processor.setValidator(validator);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfigurationTests.CustomValidatorConfiguration.TestBeanPostProcessor;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -43,6 +44,7 @@ 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.Mockito.mock;
|
||||
|
||||
/**
|
||||
@@ -159,6 +161,15 @@ class ValidationAutoConfigurationTests {
|
||||
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething("KO"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void classCanBeExcludedFromValidation() {
|
||||
load(ExcludedServiceConfiguration.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
ExcludedService service = this.context.getBean(ExcludedService.class);
|
||||
service.doSomething("Valid");
|
||||
assertThatNoException().isThrownBy(() -> service.doSomething("KO"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void validationUsesCglibProxy() {
|
||||
load(DefaultAnotherSampleService.class);
|
||||
@@ -285,6 +296,29 @@ class ValidationAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static final class ExcludedServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
ExcludedService excludedService() {
|
||||
return new ExcludedService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
MethodValidationExcludeFilter exclusionFilter() {
|
||||
return (type) -> type.equals(ExcludedService.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Validated
|
||||
static final class ExcludedService {
|
||||
|
||||
void doSomething(@Size(min = 3, max = 10) String name) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface AnotherSampleService {
|
||||
|
||||
void doSomething(@Min(42) Integer counter);
|
||||
|
||||
Reference in New Issue
Block a user