From 89581015100adc6c1c7cb52fd0bef3bfdd3a91e8 Mon Sep 17 00:00:00 2001 From: MatejNedic Date: Thu, 25 Mar 2021 20:56:07 +0100 Subject: [PATCH 1/2] Fix no such bean definition with ancestor-defined Validator See gh-25800 --- .../PrimaryDefaultValidatorPostProcessor.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java index ff32b479ed..f60b1cdf4d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java @@ -20,6 +20,7 @@ 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.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -37,6 +38,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; * as primary. * * @author Stephane Nicoll + * @author Matej Nedic */ class PrimaryDefaultValidatorPostProcessor implements ImportBeanDefinitionRegistrar, BeanFactoryAware { @@ -58,7 +60,7 @@ class PrimaryDefaultValidatorPostProcessor implements ImportBeanDefinitionRegist public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { BeanDefinition definition = getAutoConfiguredValidator(registry); if (definition != null) { - definition.setPrimary(!hasPrimarySpringValidator(registry)); + definition.setPrimary(!hasPrimarySpringValidator()); } } @@ -77,16 +79,27 @@ class PrimaryDefaultValidatorPostProcessor implements ImportBeanDefinitionRegist return this.beanFactory != null && this.beanFactory.isTypeMatch(name, type); } - private boolean hasPrimarySpringValidator(BeanDefinitionRegistry registry) { + private boolean hasPrimarySpringValidator() { String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Validator.class, false, false); for (String validatorBean : validatorBeans) { - BeanDefinition definition = registry.getBeanDefinition(validatorBean); - if (definition != null && definition.isPrimary()) { + BeanDefinition definition = searchForBeanDefinition(this.beanFactory, validatorBean); + if (definition.isPrimary()) { return true; } } return false; } + private BeanDefinition searchForBeanDefinition(ConfigurableListableBeanFactory clbf, String validatorBean) { + if (clbf.containsLocalBean(validatorBean)) { + return clbf.getBeanDefinition(validatorBean); + } + else if (clbf.getParentBeanFactory() instanceof ConfigurableListableBeanFactory) { + return searchForBeanDefinition((ConfigurableListableBeanFactory) clbf.getParentBeanFactory(), + validatorBean); + } + throw new NoSuchBeanDefinitionException(validatorBean); + } + } From cf0bd0f9590d237c735bb2bc7982b17267e23395 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 1 Apr 2021 14:44:17 +0100 Subject: [PATCH 2/2] Polish "Fix no such bean definition with ancestor-defined Validator" See gh-25800 --- .../PrimaryDefaultValidatorPostProcessor.java | 21 +++--------- .../ValidationAutoConfigurationTests.java | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java index f60b1cdf4d..7fbafabf20 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/PrimaryDefaultValidatorPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 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,8 +19,6 @@ 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.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -39,6 +37,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; * * @author Stephane Nicoll * @author Matej Nedic + * @author Andy Wilkinson */ class PrimaryDefaultValidatorPostProcessor implements ImportBeanDefinitionRegistrar, BeanFactoryAware { @@ -80,10 +79,9 @@ class PrimaryDefaultValidatorPostProcessor implements ImportBeanDefinitionRegist } private boolean hasPrimarySpringValidator() { - String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Validator.class, - false, false); + String[] validatorBeans = this.beanFactory.getBeanNamesForType(Validator.class, false, false); for (String validatorBean : validatorBeans) { - BeanDefinition definition = searchForBeanDefinition(this.beanFactory, validatorBean); + BeanDefinition definition = this.beanFactory.getBeanDefinition(validatorBean); if (definition.isPrimary()) { return true; } @@ -91,15 +89,4 @@ class PrimaryDefaultValidatorPostProcessor implements ImportBeanDefinitionRegist return false; } - private BeanDefinition searchForBeanDefinition(ConfigurableListableBeanFactory clbf, String validatorBean) { - if (clbf.containsLocalBean(validatorBean)) { - return clbf.getBeanDefinition(validatorBean); - } - else if (clbf.getParentBeanFactory() instanceof ConfigurableListableBeanFactory) { - return searchForBeanDefinition((ConfigurableListableBeanFactory) clbf.getParentBeanFactory(), - validatorBean); - } - throw new NoSuchBeanDefinitionException(validatorBean); - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java index 35df630d12..f87959495e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java @@ -26,6 +26,7 @@ import javax.validation.constraints.Size; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -127,6 +128,37 @@ class ValidationAutoConfigurationTests { }); } + @Test + void whenUserProvidesSpringValidatorInParentContextThenAutoConfiguredValidatorIsPrimary() { + new ApplicationContextRunner().withUserConfiguration(UserDefinedSpringValidatorConfig.class).run((parent) -> { + this.contextRunner.withParent(parent).run((context) -> { + assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("defaultValidator"); + assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class)) + .containsExactly("defaultValidator"); + assertThat(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context.getBeanFactory(), + org.springframework.validation.Validator.class)).containsExactly("defaultValidator", + "customValidator", "anotherCustomValidator"); + assertThat(isPrimaryBean(context, "defaultValidator")).isTrue(); + }); + }); + } + + @Test + void whenUserProvidesPrimarySpringValidatorInParentContextThenAutoConfiguredValidatorIsPrimary() { + new ApplicationContextRunner().withUserConfiguration(UserDefinedPrimarySpringValidatorConfig.class) + .run((parent) -> { + this.contextRunner.withParent(parent).run((context) -> { + assertThat(context.getBeanNamesForType(Validator.class)).containsExactly("defaultValidator"); + assertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class)) + .containsExactly("defaultValidator"); + assertThat(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context.getBeanFactory(), + org.springframework.validation.Validator.class)).containsExactly("defaultValidator", + "customValidator", "anotherCustomValidator"); + assertThat(isPrimaryBean(context, "defaultValidator")).isTrue(); + }); + }); + } + @Test void validationIsEnabled() { this.contextRunner.withUserConfiguration(SampleService.class).run((context) -> {