Browse Source

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)
pull/1316/head
Juergen Hoeller 9 years ago
parent
commit
3304efd64d
  1. 33
      spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
  2. 6
      spring-beans/src/main/java/org/springframework/beans/factory/config/ListFactoryBean.java
  3. 9
      spring-beans/src/main/java/org/springframework/beans/factory/config/MapFactoryBean.java
  4. 6
      spring-beans/src/main/java/org/springframework/beans/factory/config/SetFactoryBean.java
  5. 16
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  6. 232
      spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java
  7. 10
      spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java
  8. 10
      spring-core/src/main/java/org/springframework/core/Conventions.java
  9. 4
      spring-core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java
  10. 3
      spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
  11. 3
      spring-core/src/main/java/org/springframework/core/MethodParameter.java
  12. 54
      spring-core/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java
  13. 6
      spring-web/src/main/java/org/springframework/web/multipart/support/MultipartResolutionDelegate.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -28,7 +28,6 @@ import org.springframework.beans.BeansException; @@ -28,7 +28,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
@ -63,6 +62,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable @@ -63,6 +62,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
private Class<?> containingClass;
private volatile ResolvableType resolvableType;
/**
* Create a new descriptor for a method or constructor parameter.
@ -214,6 +215,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable @@ -214,6 +215,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
*/
public void increaseNestingLevel() {
this.nestingLevel++;
this.resolvableType = null;
if (this.methodParameter != null) {
this.methodParameter.increaseNestingLevel();
}
@ -227,6 +229,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable @@ -227,6 +229,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
*/
public void setContainingClass(Class<?> containingClass) {
this.containingClass = containingClass;
this.resolvableType = null;
if (this.methodParameter != null) {
GenericTypeResolver.resolveParameterType(this.methodParameter, containingClass);
}
@ -237,8 +240,12 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable @@ -237,8 +240,12 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
* @since 4.0
*/
public ResolvableType getResolvableType() {
return (this.field != null ? ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
ResolvableType.forMethodParameter(this.methodParameter));
if (this.resolvableType == null) {
this.resolvableType = (this.field != null ?
ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
ResolvableType.forMethodParameter(this.methodParameter));
}
return this.resolvableType;
}
/**
@ -324,31 +331,37 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable @@ -324,31 +331,37 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
/**
* Determine the generic element type of the wrapped Collection parameter/field, if any.
* @return the generic type, or {@code null} if none
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
*/
@Deprecated
public Class<?> getCollectionType() {
return (this.field != null ?
GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
org.springframework.core.GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
org.springframework.core.GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
}
/**
* Determine the generic key type of the wrapped Map parameter/field, if any.
* @return the generic type, or {@code null} if none
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
*/
@Deprecated
public Class<?> getMapKeyType() {
return (this.field != null ?
GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
org.springframework.core.GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
org.springframework.core.GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
}
/**
* Determine the generic value type of the wrapped Map parameter/field, if any.
* @return the generic type, or {@code null} if none
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
*/
@Deprecated
public Class<?> getMapValueType() {
return (this.field != null ?
GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
org.springframework.core.GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
org.springframework.core.GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
}

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2017 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,7 +21,7 @@ import java.util.List; @@ -21,7 +21,7 @@ import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.TypeConverter;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.ResolvableType;
/**
* Simple factory for shared List instances. Allows for central setup
@ -86,7 +86,7 @@ public class ListFactoryBean extends AbstractFactoryBean<List<Object>> { @@ -86,7 +86,7 @@ public class ListFactoryBean extends AbstractFactoryBean<List<Object>> {
}
Class<?> valueType = null;
if (this.targetListClass != null) {
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetListClass);
valueType = ResolvableType.forClass(this.targetListClass).asCollection().resolveGeneric();
}
if (valueType != null) {
TypeConverter converter = getBeanTypeConverter();

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2017 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,7 +21,7 @@ import java.util.Map; @@ -21,7 +21,7 @@ import java.util.Map;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.TypeConverter;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.ResolvableType;
/**
* Simple factory for shared Map instances. Allows for central setup
@ -87,8 +87,9 @@ public class MapFactoryBean extends AbstractFactoryBean<Map<Object, Object>> { @@ -87,8 +87,9 @@ public class MapFactoryBean extends AbstractFactoryBean<Map<Object, Object>> {
Class<?> keyType = null;
Class<?> valueType = null;
if (this.targetMapClass != null) {
keyType = GenericCollectionTypeResolver.getMapKeyType(this.targetMapClass);
valueType = GenericCollectionTypeResolver.getMapValueType(this.targetMapClass);
ResolvableType mapType = ResolvableType.forClass(this.targetMapClass).asMap();
keyType = mapType.resolveGeneric(0);
valueType = mapType.resolveGeneric(1);
}
if (keyType != null || valueType != null) {
TypeConverter converter = getBeanTypeConverter();

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2017 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,7 +21,7 @@ import java.util.Set; @@ -21,7 +21,7 @@ import java.util.Set;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.TypeConverter;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.ResolvableType;
/**
* Simple factory for shared Set instances. Allows for central setup
@ -86,7 +86,7 @@ public class SetFactoryBean extends AbstractFactoryBean<Set<Object>> { @@ -86,7 +86,7 @@ public class SetFactoryBean extends AbstractFactoryBean<Set<Object>> {
}
Class<?> valueType = null;
if (this.targetSetClass != null) {
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetSetClass);
valueType = ResolvableType.forClass(this.targetSetClass).asCollection().resolveGeneric();
}
if (valueType != null) {
TypeConverter converter = getBeanTypeConverter();

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

@ -1148,6 +1148,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1148,6 +1148,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
Class<?> type = descriptor.getDependencyType();
if (type.isArray()) {
Class<?> componentType = type.getComponentType();
ResolvableType resolvableType = descriptor.getResolvableType();
Class<?> resolvedArrayType = resolvableType.resolve();
if (resolvedArrayType != null && resolvedArrayType != type) {
type = resolvedArrayType;
componentType = resolvableType.getComponentType().resolve();
}
if (componentType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
@ -1164,7 +1173,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1164,7 +1173,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return result;
}
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getCollectionType();
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
@ -1184,11 +1193,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1184,11 +1193,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return result;
}
else if (Map.class == type) {
Class<?> keyType = descriptor.getMapKeyType();
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class<?> keyType = mapType.resolveGeneric(0);
if (String.class != keyType) {
return null;
}
Class<?> valueType = descriptor.getMapValueType();
Class<?> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}

232
spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java

@ -1592,12 +1592,30 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -1592,12 +1592,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
String sv = "X";
bf.registerSingleton("stringValue", sv);
Integer iv = 1;
bf.registerSingleton("integerValue", iv);
StringRepository sr = new StringRepository();
bf.registerSingleton("stringRepo", sr);
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryFieldInjectionBean bean = (RepositoryFieldInjectionBean) bf.getBean("annotatedBean");
assertSame(sv, bean.string);
assertSame(iv, bean.integer);
assertSame(1, bean.stringArray.length);
assertSame(1, bean.integerArray.length);
assertSame(sv, bean.stringArray[0]);
assertSame(iv, bean.integerArray[0]);
assertSame(1, bean.stringList.size());
assertSame(1, bean.integerList.size());
assertSame(sv, bean.stringList.get(0));
assertSame(iv, bean.integerList.get(0));
assertSame(1, bean.stringMap.size());
assertSame(1, bean.integerMap.size());
assertSame(sv, bean.stringMap.get("stringValue"));
assertSame(iv, bean.integerMap.get("integerValue"));
assertSame(sr, bean.stringRepository);
assertSame(ir, bean.integerRepository);
assertSame(1, bean.stringRepositoryArray.length);
@ -1624,12 +1642,30 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -1624,12 +1642,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSubstitutedVariables.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
String sv = "X";
bf.registerSingleton("stringValue", sv);
Integer iv = 1;
bf.registerSingleton("integerValue", iv);
StringRepository sr = new StringRepository();
bf.registerSingleton("stringRepo", sr);
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryFieldInjectionBeanWithSubstitutedVariables bean = (RepositoryFieldInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
assertSame(sv, bean.string);
assertSame(iv, bean.integer);
assertSame(1, bean.stringArray.length);
assertSame(1, bean.integerArray.length);
assertSame(sv, bean.stringArray[0]);
assertSame(iv, bean.integerArray[0]);
assertSame(1, bean.stringList.size());
assertSame(1, bean.integerList.size());
assertSame(sv, bean.stringList.get(0));
assertSame(iv, bean.integerList.get(0));
assertSame(1, bean.stringMap.size());
assertSame(1, bean.integerMap.size());
assertSame(sv, bean.stringMap.get("stringValue"));
assertSame(iv, bean.integerMap.get("integerValue"));
assertSame(sr, bean.stringRepository);
assertSame(ir, bean.integerRepository);
assertSame(1, bean.stringRepositoryArray.length);
@ -1872,12 +1908,30 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -1872,12 +1908,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
String sv = "X";
bf.registerSingleton("stringValue", sv);
Integer iv = 1;
bf.registerSingleton("integerValue", iv);
StringRepository sr = new StringRepository();
bf.registerSingleton("stringRepo", sr);
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryMethodInjectionBean bean = (RepositoryMethodInjectionBean) bf.getBean("annotatedBean");
assertSame(sv, bean.string);
assertSame(iv, bean.integer);
assertSame(1, bean.stringArray.length);
assertSame(1, bean.integerArray.length);
assertSame(sv, bean.stringArray[0]);
assertSame(iv, bean.integerArray[0]);
assertSame(1, bean.stringList.size());
assertSame(1, bean.integerList.size());
assertSame(sv, bean.stringList.get(0));
assertSame(iv, bean.integerList.get(0));
assertSame(1, bean.stringMap.size());
assertSame(1, bean.integerMap.size());
assertSame(sv, bean.stringMap.get("stringValue"));
assertSame(iv, bean.integerMap.get("integerValue"));
assertSame(sr, bean.stringRepository);
assertSame(ir, bean.integerRepository);
assertSame(1, bean.stringRepositoryArray.length);
@ -1904,12 +1958,30 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -1904,12 +1958,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBeanWithSubstitutedVariables.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
String sv = "X";
bf.registerSingleton("stringValue", sv);
Integer iv = 1;
bf.registerSingleton("integerValue", iv);
StringRepository sr = new StringRepository();
bf.registerSingleton("stringRepo", sr);
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryMethodInjectionBeanWithSubstitutedVariables bean = (RepositoryMethodInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
assertSame(sv, bean.string);
assertSame(iv, bean.integer);
assertSame(1, bean.stringArray.length);
assertSame(1, bean.integerArray.length);
assertSame(sv, bean.stringArray[0]);
assertSame(iv, bean.integerArray[0]);
assertSame(1, bean.stringList.size());
assertSame(1, bean.integerList.size());
assertSame(sv, bean.stringList.get(0));
assertSame(iv, bean.integerList.get(0));
assertSame(1, bean.stringMap.size());
assertSame(1, bean.integerMap.size());
assertSame(sv, bean.stringMap.get("stringValue"));
assertSame(iv, bean.integerMap.get("integerValue"));
assertSame(sr, bean.stringRepository);
assertSame(ir, bean.integerRepository);
assertSame(1, bean.stringRepositoryArray.length);
@ -2968,6 +3040,30 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -2968,6 +3040,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class RepositoryFieldInjectionBean {
@Autowired
public String string;
@Autowired
public Integer integer;
@Autowired
public String[] stringArray;
@Autowired
public Integer[] integerArray;
@Autowired
public List<String> stringList;
@Autowired
public List<Integer> integerList;
@Autowired
public Map<String, String> stringMap;
@Autowired
public Map<String, Integer> integerMap;
@Autowired
public Repository<String> stringRepository;
@ -2996,6 +3092,30 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -2996,6 +3092,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class RepositoryFieldInjectionBeanWithVariables<S, I> {
@Autowired
public S string;
@Autowired
public I integer;
@Autowired
public S[] stringArray;
@Autowired
public I[] integerArray;
@Autowired
public List<S> stringList;
@Autowired
public List<I> integerList;
@Autowired
public Map<String, S> stringMap;
@Autowired
public Map<String, I> integerMap;
@Autowired
public Repository<S> stringRepository;
@ -3092,6 +3212,22 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -3092,6 +3212,22 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class RepositoryMethodInjectionBean {
public String string;
public Integer integer;
public String[] stringArray;
public Integer[] integerArray;
public List<String> stringList;
public List<Integer> integerList;
public Map<String, String> stringMap;
public Map<String, Integer> integerMap;
public Repository<String> stringRepository;
public Repository<Integer> integerRepository;
@ -3108,6 +3244,46 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -3108,6 +3244,46 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public Map<String, Repository<Integer>> integerRepositoryMap;
@Autowired
public void setString(String string) {
this.string = string;
}
@Autowired
public void setInteger(Integer integer) {
this.integer = integer;
}
@Autowired
public void setStringArray(String[] stringArray) {
this.stringArray = stringArray;
}
@Autowired
public void setIntegerArray(Integer[] integerArray) {
this.integerArray = integerArray;
}
@Autowired
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
@Autowired
public void setIntegerList(List<Integer> integerList) {
this.integerList = integerList;
}
@Autowired
public void setStringMap(Map<String, String> stringMap) {
this.stringMap = stringMap;
}
@Autowired
public void setIntegerMap(Map<String, Integer> integerMap) {
this.integerMap = integerMap;
}
@Autowired
public void setStringRepository(Repository<String> stringRepository) {
this.stringRepository = stringRepository;
@ -3152,6 +3328,22 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -3152,6 +3328,22 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class RepositoryMethodInjectionBeanWithVariables<S, I> {
public S string;
public I integer;
public S[] stringArray;
public I[] integerArray;
public List<S> stringList;
public List<I> integerList;
public Map<String, S> stringMap;
public Map<String, I> integerMap;
public Repository<S> stringRepository;
public Repository<I> integerRepository;
@ -3168,6 +3360,46 @@ public class AutowiredAnnotationBeanPostProcessorTests { @@ -3168,6 +3360,46 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public Map<String, Repository<I>> integerRepositoryMap;
@Autowired
public void setString(S string) {
this.string = string;
}
@Autowired
public void setInteger(I integer) {
this.integer = integer;
}
@Autowired
public void setStringArray(S[] stringArray) {
this.stringArray = stringArray;
}
@Autowired
public void setIntegerArray(I[] integerArray) {
this.integerArray = integerArray;
}
@Autowired
public void setStringList(List<S> stringList) {
this.stringList = stringList;
}
@Autowired
public void setIntegerList(List<I> integerList) {
this.integerList = integerList;
}
@Autowired
public void setStringMap(Map<String, S> stringMap) {
this.stringMap = stringMap;
}
@Autowired
public void setIntegerMap(Map<String, I> integerMap) {
this.integerMap = integerMap;
}
@Autowired
public void setStringRepository(Repository<S> stringRepository) {
this.stringRepository = stringRepository;

10
spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -57,8 +57,8 @@ import org.springframework.beans.factory.BeanClassLoaderAware; @@ -57,8 +57,8 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.CollectionFactory;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.jmx.support.JmxUtils;
import org.springframework.jmx.support.ObjectNameManager;
import org.springframework.util.ClassUtils;
@ -546,7 +546,8 @@ public class MBeanClientInterceptor @@ -546,7 +546,8 @@ public class MBeanClientInterceptor
return convertDataArrayToTargetArray(array, targetClass);
}
else if (Collection.class.isAssignableFrom(targetClass)) {
Class<?> elementType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
Class<?> elementType =
ResolvableType.forMethodParameter(parameter).asCollection().resolveGeneric();
if (elementType != null) {
return convertDataArrayToTargetCollection(array, targetClass, elementType);
}
@ -562,7 +563,8 @@ public class MBeanClientInterceptor @@ -562,7 +563,8 @@ public class MBeanClientInterceptor
return convertDataArrayToTargetArray(array, targetClass);
}
else if (Collection.class.isAssignableFrom(targetClass)) {
Class<?> elementType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
Class<?> elementType =
ResolvableType.forMethodParameter(parameter).asCollection().resolveGeneric();
if (elementType != null) {
return convertDataArrayToTargetCollection(array, targetClass, elementType);
}

10
spring-core/src/main/java/org/springframework/core/Conventions.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -52,8 +52,8 @@ public abstract class Conventions { @@ -52,8 +52,8 @@ public abstract class Conventions {
private static final Set<Class<?>> IGNORED_INTERFACES;
static {
IGNORED_INTERFACES = Collections.unmodifiableSet(new HashSet<Class<?>>(Arrays.<Class<?>>asList(
Serializable.class, Externalizable.class, Cloneable.class, Comparable.class)));
IGNORED_INTERFACES = Collections.unmodifiableSet(new HashSet<Class<?>>(
Arrays.<Class<?>>asList(Serializable.class, Externalizable.class, Cloneable.class, Comparable.class)));
}
@ -114,7 +114,7 @@ public abstract class Conventions { @@ -114,7 +114,7 @@ public abstract class Conventions {
pluralize = true;
}
else if (Collection.class.isAssignableFrom(parameter.getParameterType())) {
valueClass = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
valueClass = ResolvableType.forMethodParameter(parameter).asCollection().resolveGeneric();
if (valueClass == null) {
throw new IllegalArgumentException(
"Cannot generate variable name for non-typed Collection parameter type");
@ -180,7 +180,7 @@ public abstract class Conventions { @@ -180,7 +180,7 @@ public abstract class Conventions {
pluralize = true;
}
else if (Collection.class.isAssignableFrom(resolvedType)) {
valueClass = GenericCollectionTypeResolver.getCollectionReturnType(method);
valueClass = ResolvableType.forMethodReturnType(method).asCollection().resolveGeneric();
if (valueClass == null) {
if (!(value instanceof Collection)) {
throw new IllegalArgumentException(

4
spring-core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2017 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.
@ -32,7 +32,9 @@ import java.util.Map; @@ -32,7 +32,9 @@ import java.util.Map;
* @author Phillip Webb
* @since 2.0
* @see ResolvableType
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
*/
@Deprecated
public abstract class GenericCollectionTypeResolver {
/**

3
spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2017 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.
@ -39,7 +39,6 @@ import org.springframework.util.ConcurrentReferenceHashMap; @@ -39,7 +39,6 @@ import org.springframework.util.ConcurrentReferenceHashMap;
* @author Sam Brannen
* @author Phillip Webb
* @since 2.5.2
* @see GenericCollectionTypeResolver
*/
public abstract class GenericTypeResolver {

3
spring-core/src/main/java/org/springframework/core/MethodParameter.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -43,7 +43,6 @@ import org.springframework.util.ClassUtils; @@ -43,7 +43,6 @@ import org.springframework.util.ClassUtils;
* @author Andy Clement
* @author Sam Brannen
* @since 2.0
* @see GenericCollectionTypeResolver
* @see org.springframework.core.annotation.SynthesizingMethodParameter
*/
public class MethodParameter {

54
spring-core/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2017 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.
@ -38,6 +38,7 @@ import static org.junit.Assert.*; @@ -38,6 +38,7 @@ import static org.junit.Assert.*;
* @author Juergen Hoeller
* @author Sam Brannen
*/
@SuppressWarnings("deprecation")
public class GenericCollectionTypeResolverTests {
protected Class<?> targetClass;
@ -46,31 +47,15 @@ public class GenericCollectionTypeResolverTests { @@ -46,31 +47,15 @@ public class GenericCollectionTypeResolverTests {
protected Type[] expectedResults;
@Before
public void setUp() throws Exception {
this.targetClass = Foo.class;
this.methods = new String[] { "a", "b", "b2", "b3", "c", "d", "d2", "d3", "e",
"e2", "e3" };
this.expectedResults = new Class[] { Integer.class, null, Set.class, Set.class,
null, Integer.class, Integer.class, Integer.class, Integer.class,
Integer.class, Integer.class };
}
protected void executeTest(String methodName) throws NoSuchMethodException {
for (int i = 0; i < this.methods.length; i++) {
if (methodName.equals(this.methods[i])) {
Method method = this.targetClass.getMethod(methodName);
Type type = getType(method);
assertEquals(this.expectedResults[i], type);
return;
}
}
throw new IllegalStateException("Bad test data");
this.methods = new String[] {"a", "b", "b2", "b3", "c", "d", "d2", "d3", "e", "e2", "e3"};
this.expectedResults = new Class<?>[] {Integer.class, null, Set.class, Set.class, null,
Integer.class, Integer.class, Integer.class, Integer.class, Integer.class, Integer.class};
}
protected Type getType(Method method) {
return GenericCollectionTypeResolver.getMapValueReturnType(method);
}
@Test
public void a() throws Exception {
@ -130,10 +115,8 @@ public class GenericCollectionTypeResolverTests { @@ -130,10 +115,8 @@ public class GenericCollectionTypeResolverTests {
@Test
public void programmaticListIntrospection() throws Exception {
Method setter = GenericObject.class.getMethod("setResourceList", List.class);
assertEquals(
Resource.class,
GenericCollectionTypeResolver.getCollectionParameterType(new MethodParameter(
setter, 0)));
assertEquals(Resource.class,
GenericCollectionTypeResolver.getCollectionParameterType(new MethodParameter(setter, 0)));
Method getter = GenericObject.class.getMethod("getResourceList");
assertEquals(Resource.class,
@ -150,6 +133,24 @@ public class GenericCollectionTypeResolverTests { @@ -150,6 +133,24 @@ public class GenericCollectionTypeResolverTests {
GenericCollectionTypeResolver.getMapValueType(CustomMap.class));
}
protected void executeTest(String methodName) throws NoSuchMethodException {
for (int i = 0; i < this.methods.length; i++) {
if (methodName.equals(this.methods[i])) {
Method method = this.targetClass.getMethod(methodName);
Type type = getType(method);
assertEquals(this.expectedResults[i], type);
return;
}
}
throw new IllegalStateException("Bad test data");
}
protected Type getType(Method method) {
return GenericCollectionTypeResolver.getMapValueReturnType(method);
}
private static abstract class CustomSet<T> extends AbstractSet<String> {
}
@ -159,8 +160,9 @@ public class GenericCollectionTypeResolverTests { @@ -159,8 +160,9 @@ public class GenericCollectionTypeResolverTests {
private static abstract class OtherCustomMap<T> implements Map<String, Integer> {
}
@SuppressWarnings("rawtypes")
private static interface Foo {
private interface Foo {
Map<String, Integer> a();

6
spring-web/src/main/java/org/springframework/web/multipart/support/MultipartResolutionDelegate.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -22,8 +22,8 @@ import java.util.List; @@ -22,8 +22,8 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.util.ClassUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
@ -155,7 +155,7 @@ public abstract class MultipartResolutionDelegate { @@ -155,7 +155,7 @@ public abstract class MultipartResolutionDelegate {
private static Class<?> getCollectionParameterType(MethodParameter methodParam) {
Class<?> paramType = methodParam.getNestedParameterType();
if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){
Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
Class<?> valueType = ResolvableType.forMethodParameter(methodParam).asCollection().resolveGeneric();
if (valueType != null) {
return valueType;
}

Loading…
Cancel
Save