Skip to content

Commit 6783ba2

Browse files
committed
@Bean-returned FactoryBean proxy delegates to actual target instance now
Issue: SPR-12915 (cherry picked from commit 1da98b0)
1 parent 8f6ac19 commit 6783ba2

File tree

2 files changed

+154
-100
lines changed

2 files changed

+154
-100
lines changed

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -289,7 +289,7 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
289289
}
290290
else {
291291
// It is a candidate FactoryBean - go ahead with enhancement
292-
return enhanceFactoryBean(factoryBean.getClass(), beanFactory, beanName);
292+
return enhanceFactoryBean(factoryBean, beanFactory, beanName);
293293
}
294294
}
295295

@@ -303,7 +303,7 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
303303
"result in a failure to process annotations such as @Autowired, " +
304304
"@Resource and @PostConstruct within the method's declaring " +
305305
"@Configuration class. Add the 'static' modifier to this method to avoid " +
306-
"these container lifecycle issues; see @Bean javadoc for complete details",
306+
"these container lifecycle issues; see @Bean javadoc for complete details.",
307307
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
308308
}
309309
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
@@ -365,11 +365,11 @@ private boolean isCurrentlyInvokedFactoryMethod(Method method) {
365365
* instance directly. If a FactoryBean instance is fetched through the container via &-dereferencing,
366366
* it will not be proxied. This too is aligned with the way XML configuration works.
367367
*/
368-
private Object enhanceFactoryBean(Class<?> fbClass, final ConfigurableBeanFactory beanFactory,
368+
private Object enhanceFactoryBean(final Object factoryBean, final ConfigurableBeanFactory beanFactory,
369369
final String beanName) throws InstantiationException, IllegalAccessException {
370370

371371
Enhancer enhancer = new Enhancer();
372-
enhancer.setSuperclass(fbClass);
372+
enhancer.setSuperclass(factoryBean.getClass());
373373
enhancer.setUseFactory(false);
374374
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
375375
enhancer.setCallback(new MethodInterceptor() {
@@ -378,7 +378,7 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr
378378
if (method.getName().equals("getObject") && args.length == 0) {
379379
return beanFactory.getBean(beanName);
380380
}
381-
return proxy.invokeSuper(obj, args);
381+
return proxy.invoke(factoryBean, args);
382382
}
383383
});
384384
return enhancer.create();
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,13 +19,17 @@
1919
import org.junit.Test;
2020

2121
import org.springframework.beans.factory.FactoryBean;
22+
import org.springframework.beans.factory.InitializingBean;
2223
import org.springframework.beans.factory.annotation.Autowired;
2324
import org.springframework.util.Assert;
2425

26+
import static org.junit.Assert.*;
27+
2528
/**
2629
* Tests cornering bug SPR-8514.
2730
*
2831
* @author Chris Beams
32+
* @author Juergen Hoeller
2933
* @since 3.1
3034
*/
3135
public class ConfigurationWithFactoryBeanAndAutowiringTests {
@@ -77,138 +81,188 @@ public void withWildcardParameterizedFactoryBeanInterfaceAsReturnType() {
7781
ctx.register(WildcardParameterizedFactoryBeanInterfaceConfig.class);
7882
ctx.refresh();
7983
}
80-
}
81-
8284

83-
class DummyBean {
84-
}
85+
@Test
86+
public void withFactoryBeanCallingBean() {
87+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
88+
ctx.register(AppConfig.class);
89+
ctx.register(FactoryBeanCallingConfig.class);
90+
ctx.refresh();
91+
assertEquals("true", ctx.getBean("myString"));
92+
}
8593

8694

87-
class MyFactoryBean implements FactoryBean<String> {
88-
@Override
89-
public String getObject() throws Exception {
90-
return "foo";
91-
}
92-
@Override
93-
public Class<String> getObjectType() {
94-
return String.class;
95-
}
96-
@Override
97-
public boolean isSingleton() {
98-
return true;
95+
static class DummyBean {
9996
}
100-
}
10197

10298

103-
class MyParameterizedFactoryBean<T> implements FactoryBean<T> {
99+
static class MyFactoryBean implements FactoryBean<String>, InitializingBean {
104100

105-
private final T obj;
101+
private boolean initialized = false;
106102

107-
public MyParameterizedFactoryBean(T obj) {
108-
this.obj = obj;
109-
}
103+
@Override
104+
public void afterPropertiesSet() throws Exception {
105+
this.initialized = true;
106+
}
107+
108+
@Override
109+
public String getObject() throws Exception {
110+
return "foo";
111+
}
112+
113+
@Override
114+
public Class<String> getObjectType() {
115+
return String.class;
116+
}
117+
118+
@Override
119+
public boolean isSingleton() {
120+
return true;
121+
}
110122

111-
@Override
112-
public T getObject() throws Exception {
113-
return obj;
123+
public String getString() {
124+
return Boolean.toString(this.initialized);
125+
}
114126
}
115127

116-
@Override
117-
@SuppressWarnings("unchecked")
118-
public Class<T> getObjectType() {
119-
return (Class<T>)obj.getClass();
128+
129+
static class MyParameterizedFactoryBean<T> implements FactoryBean<T> {
130+
131+
private final T obj;
132+
133+
public MyParameterizedFactoryBean(T obj) {
134+
this.obj = obj;
135+
}
136+
137+
@Override
138+
public T getObject() throws Exception {
139+
return obj;
140+
}
141+
142+
@Override
143+
@SuppressWarnings("unchecked")
144+
public Class<T> getObjectType() {
145+
return (Class<T>)obj.getClass();
146+
}
147+
148+
@Override
149+
public boolean isSingleton() {
150+
return true;
151+
}
120152
}
121153

122-
@Override
123-
public boolean isSingleton() {
124-
return true;
154+
155+
@Configuration
156+
static class AppConfig {
157+
158+
@Bean
159+
public DummyBean dummyBean() {
160+
return new DummyBean();
161+
}
125162
}
126-
}
127163

128164

129-
@Configuration
130-
class AppConfig {
131-
@Bean
132-
public DummyBean dummyBean() {
133-
return new DummyBean();
165+
@Configuration
166+
static class ConcreteFactoryBeanImplementationConfig {
167+
168+
@Autowired
169+
private DummyBean dummyBean;
170+
171+
@Bean
172+
public MyFactoryBean factoryBean() {
173+
Assert.notNull(dummyBean, "DummyBean was not injected.");
174+
return new MyFactoryBean();
175+
}
134176
}
135-
}
136177

137178

138-
@Configuration
139-
class ConcreteFactoryBeanImplementationConfig {
140-
@Autowired
141-
private DummyBean dummyBean;
179+
@Configuration
180+
static class ParameterizedFactoryBeanImplementationConfig {
181+
182+
@Autowired
183+
private DummyBean dummyBean;
142184

143-
@Bean
144-
public MyFactoryBean factoryBean() {
145-
Assert.notNull(dummyBean, "DummyBean was not injected.");
146-
return new MyFactoryBean();
185+
@Bean
186+
public MyParameterizedFactoryBean<String> factoryBean() {
187+
Assert.notNull(dummyBean, "DummyBean was not injected.");
188+
return new MyParameterizedFactoryBean<String>("whatev");
189+
}
147190
}
148-
}
149191

150192

151-
@Configuration
152-
class ParameterizedFactoryBeanImplementationConfig {
153-
@Autowired
154-
private DummyBean dummyBean;
193+
@Configuration
194+
static class ParameterizedFactoryBeanInterfaceConfig {
195+
196+
@Autowired
197+
private DummyBean dummyBean;
155198

156-
@Bean
157-
public MyParameterizedFactoryBean<String> factoryBean() {
158-
Assert.notNull(dummyBean, "DummyBean was not injected.");
159-
return new MyParameterizedFactoryBean<String>("whatev");
199+
@Bean
200+
public FactoryBean<String> factoryBean() {
201+
Assert.notNull(dummyBean, "DummyBean was not injected.");
202+
return new MyFactoryBean();
203+
}
160204
}
161-
}
162205

163206

164-
@Configuration
165-
class ParameterizedFactoryBeanInterfaceConfig {
166-
@Autowired
167-
private DummyBean dummyBean;
207+
@Configuration
208+
static class NonPublicParameterizedFactoryBeanInterfaceConfig {
209+
210+
@Autowired
211+
private DummyBean dummyBean;
168212

169-
@Bean
170-
public FactoryBean<String> factoryBean() {
171-
Assert.notNull(dummyBean, "DummyBean was not injected.");
172-
return new MyFactoryBean();
213+
@Bean
214+
FactoryBean<String> factoryBean() {
215+
Assert.notNull(dummyBean, "DummyBean was not injected.");
216+
return new MyFactoryBean();
217+
}
173218
}
174-
}
175219

176220

177-
@Configuration
178-
class NonPublicParameterizedFactoryBeanInterfaceConfig {
179-
@Autowired
180-
private DummyBean dummyBean;
221+
@Configuration
222+
static class RawFactoryBeanInterfaceConfig {
181223

182-
@Bean
183-
FactoryBean<String> factoryBean() {
184-
Assert.notNull(dummyBean, "DummyBean was not injected.");
185-
return new MyFactoryBean();
224+
@Autowired
225+
private DummyBean dummyBean;
226+
227+
@Bean
228+
@SuppressWarnings("rawtypes")
229+
public FactoryBean factoryBean() {
230+
Assert.notNull(dummyBean, "DummyBean was not injected.");
231+
return new MyFactoryBean();
232+
}
186233
}
187-
}
188234

189235

190-
@Configuration
191-
class RawFactoryBeanInterfaceConfig {
192-
@Autowired
193-
private DummyBean dummyBean;
236+
@Configuration
237+
static class WildcardParameterizedFactoryBeanInterfaceConfig {
194238

195-
@Bean
196-
@SuppressWarnings("rawtypes")
197-
public FactoryBean factoryBean() {
198-
Assert.notNull(dummyBean, "DummyBean was not injected.");
199-
return new MyFactoryBean();
239+
@Autowired
240+
private DummyBean dummyBean;
241+
242+
@Bean
243+
public FactoryBean<?> factoryBean() {
244+
Assert.notNull(dummyBean, "DummyBean was not injected.");
245+
return new MyFactoryBean();
246+
}
200247
}
201-
}
202248

203249

204-
@Configuration
205-
class WildcardParameterizedFactoryBeanInterfaceConfig {
206-
@Autowired
207-
private DummyBean dummyBean;
250+
@Configuration
251+
static class FactoryBeanCallingConfig {
252+
253+
@Autowired
254+
private DummyBean dummyBean;
208255

209-
@Bean
210-
public FactoryBean<?> factoryBean() {
211-
Assert.notNull(dummyBean, "DummyBean was not injected.");
212-
return new MyFactoryBean();
256+
@Bean
257+
public MyFactoryBean factoryBean() {
258+
Assert.notNull(dummyBean, "DummyBean was not injected.");
259+
return new MyFactoryBean();
260+
}
261+
262+
@Bean
263+
public String myString() {
264+
return factoryBean().getString();
265+
}
213266
}
267+
214268
}

0 commit comments

Comments
 (0)