diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java index 3f8aeb6a42c..ebc3cbf53c3 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java @@ -30,6 +30,7 @@ import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; @@ -165,6 +166,8 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP * required property check as performed by this post-processor. *

The default implementations check for the presence of the * {@link #SKIP_REQUIRED_CHECK_ATTRIBUTE} attribute in the bean definition, if any. + * It also suggests skipping in case of a bean definition with a "factory-bean" + * reference set, assuming that instance-based factories pre-populate the bean. * @param beanFactory the BeanFactory to check against * @param beanName the name of the bean to check against * @return {@code true} to skip the bean; {@code false} to process it @@ -173,7 +176,11 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP if (beanFactory == null || !beanFactory.containsBeanDefinition(beanName)) { return false; } - Object value = beanFactory.getBeanDefinition(beanName).getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE); + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); + if (beanDefinition.getFactoryBeanName() != null) { + return true; + } + Object value = beanDefinition.getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE); return (value != null && (Boolean.TRUE.equals(value) || Boolean.valueOf(value.toString()))); } diff --git a/spring-beans/src/test/java/org/springframework/beans/annotation/RequiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/annotation/RequiredAnnotationBeanPostProcessorTests.java deleted file mode 100644 index 7c728a55a29..00000000000 --- a/spring-beans/src/test/java/org/springframework/beans/annotation/RequiredAnnotationBeanPostProcessorTests.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2002-2012 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.beans.annotation; - -import static org.junit.Assert.*; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.junit.Test; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.annotation.Required; -import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; - -/** - * @author Rob Harrop - * @author Chris Beams - * @since 2.0 - */ -public final class RequiredAnnotationBeanPostProcessorTests { - - @Test - public void testWithRequiredPropertyOmitted() { - try { - DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); - BeanDefinition beanDef = BeanDefinitionBuilder - .genericBeanDefinition(RequiredTestBean.class) - .addPropertyValue("name", "Rob Harrop") - .addPropertyValue("favouriteColour", "Blue") - .addPropertyValue("jobTitle", "Grand Poobah") - .getBeanDefinition(); - factory.registerBeanDefinition("testBean", beanDef); - factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); - factory.preInstantiateSingletons(); - fail("Should have thrown BeanCreationException"); - } - catch (BeanCreationException ex) { - String message = ex.getCause().getMessage(); - assertTrue(message.indexOf("Property") > -1); - assertTrue(message.indexOf("age") > -1); - assertTrue(message.indexOf("testBean") > -1); - } - } - - @Test - public void testWithThreeRequiredPropertiesOmitted() { - try { - DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); - BeanDefinition beanDef = BeanDefinitionBuilder - .genericBeanDefinition(RequiredTestBean.class) - .addPropertyValue("name", "Rob Harrop") - .getBeanDefinition(); - factory.registerBeanDefinition("testBean", beanDef); - factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); - factory.preInstantiateSingletons(); - fail("Should have thrown BeanCreationException"); - } - catch (BeanCreationException ex) { - String message = ex.getCause().getMessage(); - assertTrue(message.indexOf("Properties") > -1); - assertTrue(message.indexOf("age") > -1); - assertTrue(message.indexOf("favouriteColour") > -1); - assertTrue(message.indexOf("jobTitle") > -1); - assertTrue(message.indexOf("testBean") > -1); - } - } - - @Test - public void testWithOnlyRequiredPropertiesSpecified() { - DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); - BeanDefinition beanDef = BeanDefinitionBuilder - .genericBeanDefinition(RequiredTestBean.class) - .addPropertyValue("age", "24") - .addPropertyValue("favouriteColour", "Blue") - .addPropertyValue("jobTitle", "Grand Poobah") - .getBeanDefinition(); - factory.registerBeanDefinition("testBean", beanDef); - factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); - factory.preInstantiateSingletons(); - RequiredTestBean bean = (RequiredTestBean) factory.getBean("testBean"); - assertEquals(24, bean.getAge()); - assertEquals("Blue", bean.getFavouriteColour()); - } - - @Test - public void testWithCustomAnnotation() { - try { - DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); - BeanDefinition beanDef = BeanDefinitionBuilder - .genericBeanDefinition(RequiredTestBean.class) - .getBeanDefinition(); - factory.registerBeanDefinition("testBean", beanDef); - RequiredAnnotationBeanPostProcessor rabpp = new RequiredAnnotationBeanPostProcessor(); - rabpp.setRequiredAnnotationType(MyRequired.class); - factory.addBeanPostProcessor(rabpp); - factory.preInstantiateSingletons(); - fail("Should have thrown BeanCreationException"); - } - catch (BeanCreationException ex) { - String message = ex.getCause().getMessage(); - assertTrue(message.indexOf("Property") > -1); - assertTrue(message.indexOf("name") > -1); - assertTrue(message.indexOf("testBean") > -1); - } - } - -} - - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@interface MyRequired { -} - - -class RequiredTestBean implements BeanNameAware, BeanFactoryAware { - - private String name; - - private int age; - - private String favouriteColour; - - private String jobTitle; - - - public int getAge() { - return age; - } - - @Required - public void setAge(int age) { - this.age = age; - } - - public String getName() { - return name; - } - - @MyRequired - public void setName(String name) { - this.name = name; - } - - public String getFavouriteColour() { - return favouriteColour; - } - - @Required - public void setFavouriteColour(String favouriteColour) { - this.favouriteColour = favouriteColour; - } - - public String getJobTitle() { - return jobTitle; - } - - @Required - public void setJobTitle(String jobTitle) { - this.jobTitle = jobTitle; - } - - @Override - @Required - public void setBeanName(String name) { - } - - @Override - @Required - public void setBeanFactory(BeanFactory beanFactory) { - } - -} diff --git a/spring-beans/src/test/java/org/springframework/beans/annotation/AnnotationBeanWiringInfoResolverTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolverTests.java similarity index 98% rename from spring-beans/src/test/java/org/springframework/beans/annotation/AnnotationBeanWiringInfoResolverTests.java rename to spring-beans/src/test/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolverTests.java index b623750f363..b4b9ec2a288 100644 --- a/spring-beans/src/test/java/org/springframework/beans/annotation/AnnotationBeanWiringInfoResolverTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AnnotationBeanWiringInfoResolverTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.beans.annotation; +package org.springframework.beans.factory.annotation; import static org.junit.Assert.*; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessorTests.java new file mode 100644 index 00000000000..9daf6383733 --- /dev/null +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessorTests.java @@ -0,0 +1,262 @@ +/* + * Copyright 2002-2012 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.beans.factory.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.Test; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; + +import static org.junit.Assert.*; + +/** + * @author Rob Harrop + * @author Chris Beams + * @since 2.0 + */ +public final class RequiredAnnotationBeanPostProcessorTests { + + @Test + public void testWithRequiredPropertyOmitted() { + try { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + BeanDefinition beanDef = BeanDefinitionBuilder + .genericBeanDefinition(RequiredTestBean.class) + .addPropertyValue("name", "Rob Harrop") + .addPropertyValue("favouriteColour", "Blue") + .addPropertyValue("jobTitle", "Grand Poobah") + .getBeanDefinition(); + factory.registerBeanDefinition("testBean", beanDef); + factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); + factory.preInstantiateSingletons(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + String message = ex.getCause().getMessage(); + assertTrue(message.contains("Property")); + assertTrue(message.contains("age")); + assertTrue(message.contains("testBean")); + } + } + + @Test + public void testWithThreeRequiredPropertiesOmitted() { + try { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + BeanDefinition beanDef = BeanDefinitionBuilder + .genericBeanDefinition(RequiredTestBean.class) + .addPropertyValue("name", "Rob Harrop") + .getBeanDefinition(); + factory.registerBeanDefinition("testBean", beanDef); + factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); + factory.preInstantiateSingletons(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + String message = ex.getCause().getMessage(); + assertTrue(message.contains("Properties")); + assertTrue(message.contains("age")); + assertTrue(message.contains("favouriteColour")); + assertTrue(message.contains("jobTitle")); + assertTrue(message.contains("testBean")); + } + } + + @Test + public void testWithAllRequiredPropertiesSpecified() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + BeanDefinition beanDef = BeanDefinitionBuilder + .genericBeanDefinition(RequiredTestBean.class) + .addPropertyValue("age", "24") + .addPropertyValue("favouriteColour", "Blue") + .addPropertyValue("jobTitle", "Grand Poobah") + .getBeanDefinition(); + factory.registerBeanDefinition("testBean", beanDef); + factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); + factory.preInstantiateSingletons(); + RequiredTestBean bean = (RequiredTestBean) factory.getBean("testBean"); + assertEquals(24, bean.getAge()); + assertEquals("Blue", bean.getFavouriteColour()); + } + + @Test + public void testWithCustomAnnotation() { + try { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + BeanDefinition beanDef = BeanDefinitionBuilder + .genericBeanDefinition(RequiredTestBean.class) + .getBeanDefinition(); + factory.registerBeanDefinition("testBean", beanDef); + RequiredAnnotationBeanPostProcessor rabpp = new RequiredAnnotationBeanPostProcessor(); + rabpp.setRequiredAnnotationType(MyRequired.class); + factory.addBeanPostProcessor(rabpp); + factory.preInstantiateSingletons(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + String message = ex.getCause().getMessage(); + assertTrue(message.contains("Property")); + assertTrue(message.contains("name")); + assertTrue(message.contains("testBean")); + } + } + + @Test + public void testWithStaticFactoryMethod() { + try { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + BeanDefinition beanDef = BeanDefinitionBuilder + .genericBeanDefinition(RequiredTestBean.class) + .setFactoryMethod("create") + .addPropertyValue("name", "Rob Harrop") + .addPropertyValue("favouriteColour", "Blue") + .addPropertyValue("jobTitle", "Grand Poobah") + .getBeanDefinition(); + factory.registerBeanDefinition("testBean", beanDef); + factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); + factory.preInstantiateSingletons(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + String message = ex.getCause().getMessage(); + assertTrue(message.contains("Property")); + assertTrue(message.contains("age")); + assertTrue(message.contains("testBean")); + } + } + + @Test + public void testWithStaticFactoryMethodAndRequiredPropertiesSpecified() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + BeanDefinition beanDef = BeanDefinitionBuilder + .genericBeanDefinition(RequiredTestBean.class) + .setFactoryMethod("create") + .addPropertyValue("age", "24") + .addPropertyValue("favouriteColour", "Blue") + .addPropertyValue("jobTitle", "Grand Poobah") + .getBeanDefinition(); + factory.registerBeanDefinition("testBean", beanDef); + factory.addBeanPostProcessor(new RequiredAnnotationBeanPostProcessor()); + factory.preInstantiateSingletons(); + RequiredTestBean bean = (RequiredTestBean) factory.getBean("testBean"); + assertEquals(24, bean.getAge()); + assertEquals("Blue", bean.getFavouriteColour()); + } + + @Test + public void testWithFactoryBean() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + RootBeanDefinition beanDef = new RootBeanDefinition(RequiredTestBean.class); + beanDef.setFactoryBeanName("testBeanFactory"); + beanDef.setFactoryMethodName("create"); + factory.registerBeanDefinition("testBean", beanDef); + factory.registerBeanDefinition("testBeanFactory", new RootBeanDefinition(RequiredTestBeanFactory.class)); + RequiredAnnotationBeanPostProcessor bpp = new RequiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(factory); + factory.addBeanPostProcessor(bpp); + factory.preInstantiateSingletons(); + } + + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface MyRequired { + } + + + public static class RequiredTestBean implements BeanNameAware, BeanFactoryAware { + + private String name; + + private int age; + + private String favouriteColour; + + private String jobTitle; + + + public int getAge() { + return age; + } + + @Required + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + @MyRequired + public void setName(String name) { + this.name = name; + } + + public String getFavouriteColour() { + return favouriteColour; + } + + @Required + public void setFavouriteColour(String favouriteColour) { + this.favouriteColour = favouriteColour; + } + + public String getJobTitle() { + return jobTitle; + } + + @Required + public void setJobTitle(String jobTitle) { + this.jobTitle = jobTitle; + } + + @Override + @Required + public void setBeanName(String name) { + } + + @Override + @Required + public void setBeanFactory(BeanFactory beanFactory) { + } + + public static RequiredTestBean create() { + return new RequiredTestBean(); + } + } + + + public static class RequiredTestBeanFactory { + + public RequiredTestBean create() { + return new RequiredTestBean(); + } + } + +}