Skip to content

Commit 3304efd

Browse files
committed
Consistent type variable resolution for arrays/collections (in particular at field level)
Deprecating GenericCollectionTypeResolver in favor of direct ResolvableType usage. Issue: SPR-15160 (cherry picked from commit 5e946c2)
1 parent b97e7d5 commit 3304efd

File tree

13 files changed

+326
-66
lines changed

13 files changed

+326
-66
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -28,7 +28,6 @@
2828
import org.springframework.beans.factory.BeanFactory;
2929
import org.springframework.beans.factory.InjectionPoint;
3030
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
31-
import org.springframework.core.GenericCollectionTypeResolver;
3231
import org.springframework.core.GenericTypeResolver;
3332
import org.springframework.core.MethodParameter;
3433
import org.springframework.core.ParameterNameDiscoverer;
@@ -63,6 +62,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
6362

6463
private Class<?> containingClass;
6564

65+
private volatile ResolvableType resolvableType;
66+
6667

6768
/**
6869
* Create a new descriptor for a method or constructor parameter.
@@ -214,6 +215,7 @@ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFacto
214215
*/
215216
public void increaseNestingLevel() {
216217
this.nestingLevel++;
218+
this.resolvableType = null;
217219
if (this.methodParameter != null) {
218220
this.methodParameter.increaseNestingLevel();
219221
}
@@ -227,6 +229,7 @@ public void increaseNestingLevel() {
227229
*/
228230
public void setContainingClass(Class<?> containingClass) {
229231
this.containingClass = containingClass;
232+
this.resolvableType = null;
230233
if (this.methodParameter != null) {
231234
GenericTypeResolver.resolveParameterType(this.methodParameter, containingClass);
232235
}
@@ -237,8 +240,12 @@ public void setContainingClass(Class<?> containingClass) {
237240
* @since 4.0
238241
*/
239242
public ResolvableType getResolvableType() {
240-
return (this.field != null ? ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
241-
ResolvableType.forMethodParameter(this.methodParameter));
243+
if (this.resolvableType == null) {
244+
this.resolvableType = (this.field != null ?
245+
ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
246+
ResolvableType.forMethodParameter(this.methodParameter));
247+
}
248+
return this.resolvableType;
242249
}
243250

244251
/**
@@ -324,31 +331,37 @@ else if (type instanceof ParameterizedType) {
324331
/**
325332
* Determine the generic element type of the wrapped Collection parameter/field, if any.
326333
* @return the generic type, or {@code null} if none
334+
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
327335
*/
336+
@Deprecated
328337
public Class<?> getCollectionType() {
329338
return (this.field != null ?
330-
GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
331-
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
339+
org.springframework.core.GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
340+
org.springframework.core.GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
332341
}
333342

334343
/**
335344
* Determine the generic key type of the wrapped Map parameter/field, if any.
336345
* @return the generic type, or {@code null} if none
346+
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
337347
*/
348+
@Deprecated
338349
public Class<?> getMapKeyType() {
339350
return (this.field != null ?
340-
GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
341-
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
351+
org.springframework.core.GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
352+
org.springframework.core.GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
342353
}
343354

344355
/**
345356
* Determine the generic value type of the wrapped Map parameter/field, if any.
346357
* @return the generic type, or {@code null} if none
358+
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
347359
*/
360+
@Deprecated
348361
public Class<?> getMapValueType() {
349362
return (this.field != null ?
350-
GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
351-
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
363+
org.springframework.core.GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
364+
org.springframework.core.GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
352365
}
353366

354367

spring-beans/src/main/java/org/springframework/beans/factory/config/ListFactoryBean.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -21,7 +21,7 @@
2121

2222
import org.springframework.beans.BeanUtils;
2323
import org.springframework.beans.TypeConverter;
24-
import org.springframework.core.GenericCollectionTypeResolver;
24+
import org.springframework.core.ResolvableType;
2525

2626
/**
2727
* Simple factory for shared List instances. Allows for central setup
@@ -86,7 +86,7 @@ protected List<Object> createInstance() {
8686
}
8787
Class<?> valueType = null;
8888
if (this.targetListClass != null) {
89-
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetListClass);
89+
valueType = ResolvableType.forClass(this.targetListClass).asCollection().resolveGeneric();
9090
}
9191
if (valueType != null) {
9292
TypeConverter converter = getBeanTypeConverter();

spring-beans/src/main/java/org/springframework/beans/factory/config/MapFactoryBean.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2008 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -21,7 +21,7 @@
2121

2222
import org.springframework.beans.BeanUtils;
2323
import org.springframework.beans.TypeConverter;
24-
import org.springframework.core.GenericCollectionTypeResolver;
24+
import org.springframework.core.ResolvableType;
2525

2626
/**
2727
* Simple factory for shared Map instances. Allows for central setup
@@ -87,8 +87,9 @@ protected Map<Object, Object> createInstance() {
8787
Class<?> keyType = null;
8888
Class<?> valueType = null;
8989
if (this.targetMapClass != null) {
90-
keyType = GenericCollectionTypeResolver.getMapKeyType(this.targetMapClass);
91-
valueType = GenericCollectionTypeResolver.getMapValueType(this.targetMapClass);
90+
ResolvableType mapType = ResolvableType.forClass(this.targetMapClass).asMap();
91+
keyType = mapType.resolveGeneric(0);
92+
valueType = mapType.resolveGeneric(1);
9293
}
9394
if (keyType != null || valueType != null) {
9495
TypeConverter converter = getBeanTypeConverter();

spring-beans/src/main/java/org/springframework/beans/factory/config/SetFactoryBean.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2008 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -21,7 +21,7 @@
2121

2222
import org.springframework.beans.BeanUtils;
2323
import org.springframework.beans.TypeConverter;
24-
import org.springframework.core.GenericCollectionTypeResolver;
24+
import org.springframework.core.ResolvableType;
2525

2626
/**
2727
* Simple factory for shared Set instances. Allows for central setup
@@ -86,7 +86,7 @@ protected Set<Object> createInstance() {
8686
}
8787
Class<?> valueType = null;
8888
if (this.targetSetClass != null) {
89-
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetSetClass);
89+
valueType = ResolvableType.forClass(this.targetSetClass).asCollection().resolveGeneric();
9090
}
9191
if (valueType != null) {
9292
TypeConverter converter = getBeanTypeConverter();

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,15 @@ private Object resolveMultipleBeans(DependencyDescriptor descriptor, String bean
11481148
Class<?> type = descriptor.getDependencyType();
11491149
if (type.isArray()) {
11501150
Class<?> componentType = type.getComponentType();
1151+
ResolvableType resolvableType = descriptor.getResolvableType();
1152+
Class<?> resolvedArrayType = resolvableType.resolve();
1153+
if (resolvedArrayType != null && resolvedArrayType != type) {
1154+
type = resolvedArrayType;
1155+
componentType = resolvableType.getComponentType().resolve();
1156+
}
1157+
if (componentType == null) {
1158+
return null;
1159+
}
11511160
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
11521161
new MultiElementDescriptor(descriptor));
11531162
if (matchingBeans.isEmpty()) {
@@ -1164,7 +1173,7 @@ private Object resolveMultipleBeans(DependencyDescriptor descriptor, String bean
11641173
return result;
11651174
}
11661175
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
1167-
Class<?> elementType = descriptor.getCollectionType();
1176+
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
11681177
if (elementType == null) {
11691178
return null;
11701179
}
@@ -1184,11 +1193,12 @@ else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
11841193
return result;
11851194
}
11861195
else if (Map.class == type) {
1187-
Class<?> keyType = descriptor.getMapKeyType();
1196+
ResolvableType mapType = descriptor.getResolvableType().asMap();
1197+
Class<?> keyType = mapType.resolveGeneric(0);
11881198
if (String.class != keyType) {
11891199
return null;
11901200
}
1191-
Class<?> valueType = descriptor.getMapValueType();
1201+
Class<?> valueType = mapType.resolveGeneric(1);
11921202
if (valueType == null) {
11931203
return null;
11941204
}

0 commit comments

Comments
 (0)