diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java index 52986ab923..5d7e801cc4 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -364,8 +364,20 @@ class ConfigurationClassEnhancer { if (alreadyInCreation) { beanFactory.setCurrentlyInCreation(beanName, false); } - Object beanInstance = (!ObjectUtils.isEmpty(beanMethodArgs) ? - beanFactory.getBean(beanName, beanMethodArgs) : beanFactory.getBean(beanName)); + boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs); + if (useArgs && beanFactory.isSingleton(beanName)) { + // Stubbed null arguments just for reference purposes, + // expecting them to be autowired for regular singleton references? + // A safe assumption since @Bean singleton arguments cannot be optional... + for (Object arg : beanMethodArgs) { + if (arg == null) { + useArgs = false; + break; + } + } + } + Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) : + beanFactory.getBean(beanName)); if (beanInstance != null && !ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) { String msg = String.format("@Bean method %s.%s called as a bean reference " + "for type [%s] but overridden by non-compatible bean instance of type [%s].", diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index 6c9a47a458..a1feb216c7 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -592,17 +592,23 @@ public class ConfigurationClassPostProcessorTests { } @Test - public void testPrototypeArgumentsThroughBeanMethodCall() { + public void testPrototypeArgumentThroughBeanMethodCall() { ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithPrototype.class); ctx.getBean(FooFactory.class).createFoo(new BarArgument()); } @Test - public void testSingletonArgumentsThroughBeanMethodCall() { + public void testSingletonArgumentThroughBeanMethodCall() { ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithSingleton.class); ctx.getBean(FooFactory.class).createFoo(new BarArgument()); } + @Test + public void testNullArgumentThroughBeanMethodCall() { + ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithNull.class); + ctx.getBean("aFoo"); + } + // ------------------------------------------------------------------------- @@ -1137,7 +1143,7 @@ public class ConfigurationClassPostProcessorTests { @Bean @Scope("prototype") - public DependingFoo foo(final BarArgument bar) { + public DependingFoo foo(BarArgument bar) { return new DependingFoo(bar); } @@ -1145,7 +1151,7 @@ public class ConfigurationClassPostProcessorTests { public FooFactory fooFactory() { return new FooFactory() { @Override - public DependingFoo createFoo(final BarArgument bar) { + public DependingFoo createFoo(BarArgument bar) { return foo(bar); } }; @@ -1156,7 +1162,7 @@ public class ConfigurationClassPostProcessorTests { static class BeanArgumentConfigWithSingleton { @Bean @Lazy - public DependingFoo foo(final BarArgument bar) { + public DependingFoo foo(BarArgument bar) { return new DependingFoo(bar); } @@ -1164,19 +1170,39 @@ public class ConfigurationClassPostProcessorTests { public FooFactory fooFactory() { return new FooFactory() { @Override - public DependingFoo createFoo(final BarArgument bar) { + public DependingFoo createFoo(BarArgument bar) { return foo(bar); } }; } } + @Configuration + static class BeanArgumentConfigWithNull { + + @Bean + public DependingFoo aFoo() { + return foo(null); + } + + @Bean @Lazy + public DependingFoo foo(BarArgument bar) { + return new DependingFoo(bar); + } + + @Bean + public BarArgument bar() { + return new BarArgument(); + } + } + static class BarArgument { } static class DependingFoo { DependingFoo(BarArgument bar) { + Assert.notNull(bar); } }