Refine validator and MVC validator configuration
This commit ensures that a primary JSR 303 and Spring Validator will be exposed if the auto-configuration kicks in. As `LocalValidatorFactoryBean` exposes 3 contracts (JSR-303 `Validator` and `ValidatorFactory` as well as the `Spring` validator one), this makes sure that those types can be injected by type. `LocalValidatorFactoryBean` exposes 3 contracts and we're only checking for the absence of a `javax.validation.Validator` to auto-configure a `LocalValidatorFactoryBean`. If no standard JSR validator exists but a Spring's `Validator` exists and is primary, we shouldn't flag the auto-configured one as `@Primary`. Previous iterations on this feature have made sure that we'll auto-configure at most one `javax.validation.Validator` so not flagging it `@Primary` is no problem. This commit also restores and adds tests that validates `ValidationAutoConfiguration` will configure a JSR validator even if a Spring Validator is present. This effectively fixes gh-8495 in a different way. Closes gh-8979 Closes gh-8976pull/9065/head
parent
f42998f5ca
commit
1de2316a0b
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.autoconfigure.validation;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
/**
|
||||
* Enable the {@code Primary} flag on the auto-configured validator if necessary.
|
||||
* <p>
|
||||
* As {@link LocalValidatorFactoryBean} exposes 3 validator related contracts and we're
|
||||
* only checking for the absence {@link javax.validation.Validator}, we should flag the
|
||||
* auto-configured validator as primary only if no Spring's {@link Validator} is flagged
|
||||
* as primary.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class PrimaryDefaultValidatorPostProcessor
|
||||
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* The bean name of the auto-configured Validator.
|
||||
*/
|
||||
private static final String VALIDATOR_BEAN_NAME = "defaultValidator";
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
if (this.beanFactory == null) {
|
||||
return;
|
||||
}
|
||||
if (!registry.containsBeanDefinition(VALIDATOR_BEAN_NAME)) {
|
||||
return;
|
||||
}
|
||||
BeanDefinition def = registry.getBeanDefinition(VALIDATOR_BEAN_NAME);
|
||||
if (def != null
|
||||
&& this.beanFactory.isTypeMatch(VALIDATOR_BEAN_NAME, LocalValidatorFactoryBean.class)
|
||||
&& def.getRole() == BeanDefinition.ROLE_INFRASTRUCTURE) {
|
||||
def.setPrimary(!hasPrimarySpringValidator(registry));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasPrimarySpringValidator(BeanDefinitionRegistry registry) {
|
||||
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
this.beanFactory, Validator.class, false, false);
|
||||
for (String validatorBean : validatorBeans) {
|
||||
BeanDefinition def = registry.getBeanDefinition(validatorBean);
|
||||
if (def != null && def.isPrimary()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue