diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java index 1a3a2c0bcd8..a54002c0b04 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * 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. @@ -21,6 +21,7 @@ import java.io.ObjectInputStream; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import org.springframework.core.GenericCollectionTypeResolver; @@ -56,6 +57,8 @@ public class DependencyDescriptor implements Serializable { private final boolean eager; + private int nestingLevel = 1; + private transient Annotation[] fieldAnnotations; @@ -153,6 +156,13 @@ public class DependencyDescriptor implements Serializable { } + public void increaseNestingLevel() { + this.nestingLevel++; + if (this.methodParameter != null) { + this.methodParameter.increaseNestingLevel(); + } + } + /** * Initialize parameter name discovery for the underlying method parameter, if any. *
This method does not actually try to retrieve the parameter name at
@@ -178,15 +188,30 @@ public class DependencyDescriptor implements Serializable {
* @return the declared type (never null)
*/
public Class> getDependencyType() {
- return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType());
- }
-
- /**
- * Determine the generic type of the wrapped parameter/field.
- * @return the generic type (never null)
- */
- public Type getGenericDependencyType() {
- return (this.field != null ? this.field.getGenericType() : this.methodParameter.getGenericParameterType());
+ if (this.field != null) {
+ if (this.nestingLevel > 1) {
+ Type type = this.field.getGenericType();
+ if (type instanceof ParameterizedType) {
+ Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
+ if (arg instanceof Class) {
+ return (Class) arg;
+ }
+ else if (arg instanceof ParameterizedType) {
+ arg = ((ParameterizedType) arg).getRawType();
+ if (arg instanceof Class) {
+ return (Class) arg;
+ }
+ }
+ }
+ return Object.class;
+ }
+ else {
+ return this.field.getType();
+ }
+ }
+ else {
+ return this.methodParameter.getNestedParameterType();
+ }
}
/**
@@ -195,7 +220,7 @@ public class DependencyDescriptor implements Serializable {
*/
public Class> getCollectionType() {
return (this.field != null ?
- GenericCollectionTypeResolver.getCollectionFieldType(this.field) :
+ GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
}
@@ -205,7 +230,7 @@ public class DependencyDescriptor implements Serializable {
*/
public Class> getMapKeyType() {
return (this.field != null ?
- GenericCollectionTypeResolver.getMapKeyFieldType(this.field) :
+ GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
}
@@ -215,7 +240,7 @@ public class DependencyDescriptor implements Serializable {
*/
public Class> getMapValueType() {
return (this.field != null ?
- GenericCollectionTypeResolver.getMapValueFieldType(this.field) :
+ GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
}
@@ -248,13 +273,18 @@ public class DependencyDescriptor implements Serializable {
if (this.fieldName != null) {
this.field = this.declaringClass.getDeclaredField(this.fieldName);
}
- else if (this.methodName != null) {
- this.methodParameter = new MethodParameter(
- this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
- }
else {
- this.methodParameter = new MethodParameter(
- this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
+ if (this.methodName != null) {
+ this.methodParameter = new MethodParameter(
+ this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
+ }
+ else {
+ this.methodParameter = new MethodParameter(
+ this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
+ }
+ for (int i = 1; i < this.nestingLevel; i++) {
+ this.methodParameter.increaseNestingLevel();
+ }
}
}
catch (Throwable ex) {
diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
index 55c4c7860b8..6f7e75c9e58 100644
--- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
+++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * 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.
@@ -1000,27 +1000,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private final String beanName;
- private final Class type;
-
public DependencyObjectFactory(DependencyDescriptor descriptor, String beanName) {
this.descriptor = descriptor;
this.beanName = beanName;
- this.type = determineObjectFactoryType();
- }
-
- private Class determineObjectFactoryType() {
- Type type = this.descriptor.getGenericDependencyType();
- if (type instanceof ParameterizedType) {
- Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
- if (arg instanceof Class) {
- return (Class) arg;
- }
- }
- return Object.class;
+ this.descriptor.increaseNestingLevel();
}
public Object getObject() throws BeansException {
- return doResolveDependency(this.descriptor, this.type, this.beanName, null, null);
+ return doResolveDependency(this.descriptor, this.descriptor.getDependencyType(), this.beanName, null, null);
}
}
diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java
index 0621e87415f..51ae86cd6c0 100644
--- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java
+++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/annotation/InjectAnnotationBeanPostProcessorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * 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.
@@ -23,7 +23,6 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
-import static org.junit.Assert.*;
import org.junit.Test;
import test.beans.ITestBean;
import test.beans.IndexedTestBean;
@@ -40,6 +39,8 @@ import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.util.SerializationTestUtils;
+import static org.junit.Assert.*;
+
/**
* Unit tests for {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor}
* processing the JSR-303 {@link javax.inject.Inject} annotation.
@@ -206,8 +207,8 @@ public class InjectAnnotationBeanPostProcessorTests {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
- bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(
- ConstructorsCollectionResourceInjectionBean.class));
+ bf.registerBeanDefinition("annotatedBean",
+ new RootBeanDefinition(ConstructorsCollectionResourceInjectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
NestedTestBean ntb1 = new NestedTestBean();
@@ -415,6 +416,74 @@ public class InjectAnnotationBeanPostProcessorTests {
bf.destroySingletons();
}
+ @Test
+ public void testObjectFactoryWithTypedListField() throws Exception {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
+ bpp.setBeanFactory(bf);
+ bf.addBeanPostProcessor(bpp);
+ bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListFieldInjectionBean.class));
+ bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
+ bf.setSerializationId("test");
+
+ ObjectFactoryListFieldInjectionBean bean = (ObjectFactoryListFieldInjectionBean) bf.getBean("annotatedBean");
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bean = (ObjectFactoryListFieldInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bf.destroySingletons();
+ }
+
+ @Test
+ public void testObjectFactoryWithTypedListMethod() throws Exception {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
+ bpp.setBeanFactory(bf);
+ bf.addBeanPostProcessor(bpp);
+ bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListMethodInjectionBean.class));
+ bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
+ bf.setSerializationId("test");
+
+ ObjectFactoryListMethodInjectionBean bean = (ObjectFactoryListMethodInjectionBean) bf.getBean("annotatedBean");
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bean = (ObjectFactoryListMethodInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bf.destroySingletons();
+ }
+
+ @Test
+ public void testObjectFactoryWithTypedMapField() throws Exception {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
+ bpp.setBeanFactory(bf);
+ bf.addBeanPostProcessor(bpp);
+ bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapFieldInjectionBean.class));
+ bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
+ bf.setSerializationId("test");
+
+ ObjectFactoryMapFieldInjectionBean bean = (ObjectFactoryMapFieldInjectionBean) bf.getBean("annotatedBean");
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bean = (ObjectFactoryMapFieldInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bf.destroySingletons();
+ }
+
+ @Test
+ public void testObjectFactoryWithTypedMapMethod() throws Exception {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
+ bpp.setBeanFactory(bf);
+ bf.addBeanPostProcessor(bpp);
+ bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapMethodInjectionBean.class));
+ bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
+ bf.setSerializationId("test");
+
+ ObjectFactoryMapMethodInjectionBean bean = (ObjectFactoryMapMethodInjectionBean) bf.getBean("annotatedBean");
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bean = (ObjectFactoryMapMethodInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
+ assertSame(bf.getBean("testBean"), bean.getTestBean());
+ bf.destroySingletons();
+ }
+
/**
* Verifies that a dependency on a {@link org.springframework.beans.factory.FactoryBean} can be autowired via
* {@link org.springframework.beans.factory.annotation.Autowired @Inject}, specifically addressing the JIRA issue
@@ -835,6 +904,66 @@ public class InjectAnnotationBeanPostProcessorTests {
}
+ public static class ObjectFactoryListFieldInjectionBean implements Serializable {
+
+ @Inject
+ private Provider> testBeanFactory;
+
+ public void setTestBeanFactory(Provider
> testBeanFactory) {
+ this.testBeanFactory = testBeanFactory;
+ }
+
+ public TestBean getTestBean() {
+ return this.testBeanFactory.get().get(0);
+ }
+ }
+
+
+ public static class ObjectFactoryListMethodInjectionBean implements Serializable {
+
+ private Provider
> testBeanFactory;
+
+ @Inject
+ public void setTestBeanFactory(Provider
> testBeanFactory) {
+ this.testBeanFactory = testBeanFactory;
+ }
+
+ public TestBean getTestBean() {
+ return this.testBeanFactory.get().get(0);
+ }
+ }
+
+
+ public static class ObjectFactoryMapFieldInjectionBean implements Serializable {
+
+ @Inject
+ private Provider