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)
This commit is contained in:
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -28,7 +28,6 @@ import org.springframework.beans.BeansException;
|
|||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.InjectionPoint;
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
@@ -63,6 +62,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
|||||||
|
|
||||||
private Class<?> containingClass;
|
private Class<?> containingClass;
|
||||||
|
|
||||||
|
private volatile ResolvableType resolvableType;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new descriptor for a method or constructor parameter.
|
* Create a new descriptor for a method or constructor parameter.
|
||||||
@@ -214,6 +215,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
|||||||
*/
|
*/
|
||||||
public void increaseNestingLevel() {
|
public void increaseNestingLevel() {
|
||||||
this.nestingLevel++;
|
this.nestingLevel++;
|
||||||
|
this.resolvableType = null;
|
||||||
if (this.methodParameter != null) {
|
if (this.methodParameter != null) {
|
||||||
this.methodParameter.increaseNestingLevel();
|
this.methodParameter.increaseNestingLevel();
|
||||||
}
|
}
|
||||||
@@ -227,6 +229,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
|||||||
*/
|
*/
|
||||||
public void setContainingClass(Class<?> containingClass) {
|
public void setContainingClass(Class<?> containingClass) {
|
||||||
this.containingClass = containingClass;
|
this.containingClass = containingClass;
|
||||||
|
this.resolvableType = null;
|
||||||
if (this.methodParameter != null) {
|
if (this.methodParameter != null) {
|
||||||
GenericTypeResolver.resolveParameterType(this.methodParameter, containingClass);
|
GenericTypeResolver.resolveParameterType(this.methodParameter, containingClass);
|
||||||
}
|
}
|
||||||
@@ -237,8 +240,12 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
|||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public ResolvableType getResolvableType() {
|
public ResolvableType getResolvableType() {
|
||||||
return (this.field != null ? ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
|
if (this.resolvableType == null) {
|
||||||
ResolvableType.forMethodParameter(this.methodParameter));
|
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
|
|||||||
/**
|
/**
|
||||||
* Determine the generic element type of the wrapped Collection parameter/field, if any.
|
* Determine the generic element type of the wrapped Collection parameter/field, if any.
|
||||||
* @return the generic type, or {@code null} if none
|
* @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() {
|
public Class<?> getCollectionType() {
|
||||||
return (this.field != null ?
|
return (this.field != null ?
|
||||||
GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
|
org.springframework.core.GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
|
||||||
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
|
org.springframework.core.GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the generic key type of the wrapped Map parameter/field, if any.
|
* Determine the generic key type of the wrapped Map parameter/field, if any.
|
||||||
* @return the generic type, or {@code null} if none
|
* @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() {
|
public Class<?> getMapKeyType() {
|
||||||
return (this.field != null ?
|
return (this.field != null ?
|
||||||
GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
|
org.springframework.core.GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
|
||||||
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
|
org.springframework.core.GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the generic value type of the wrapped Map parameter/field, if any.
|
* Determine the generic value type of the wrapped Map parameter/field, if any.
|
||||||
* @return the generic type, or {@code null} if none
|
* @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() {
|
public Class<?> getMapValueType() {
|
||||||
return (this.field != null ?
|
return (this.field != null ?
|
||||||
GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
|
org.springframework.core.GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
|
||||||
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
org.springframework.core.GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,7 +21,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.TypeConverter;
|
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
|
* Simple factory for shared List instances. Allows for central setup
|
||||||
@@ -86,7 +86,7 @@ public class ListFactoryBean extends AbstractFactoryBean<List<Object>> {
|
|||||||
}
|
}
|
||||||
Class<?> valueType = null;
|
Class<?> valueType = null;
|
||||||
if (this.targetListClass != null) {
|
if (this.targetListClass != null) {
|
||||||
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetListClass);
|
valueType = ResolvableType.forClass(this.targetListClass).asCollection().resolveGeneric();
|
||||||
}
|
}
|
||||||
if (valueType != null) {
|
if (valueType != null) {
|
||||||
TypeConverter converter = getBeanTypeConverter();
|
TypeConverter converter = getBeanTypeConverter();
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,7 +21,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.TypeConverter;
|
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
|
* Simple factory for shared Map instances. Allows for central setup
|
||||||
@@ -87,8 +87,9 @@ public class MapFactoryBean extends AbstractFactoryBean<Map<Object, Object>> {
|
|||||||
Class<?> keyType = null;
|
Class<?> keyType = null;
|
||||||
Class<?> valueType = null;
|
Class<?> valueType = null;
|
||||||
if (this.targetMapClass != null) {
|
if (this.targetMapClass != null) {
|
||||||
keyType = GenericCollectionTypeResolver.getMapKeyType(this.targetMapClass);
|
ResolvableType mapType = ResolvableType.forClass(this.targetMapClass).asMap();
|
||||||
valueType = GenericCollectionTypeResolver.getMapValueType(this.targetMapClass);
|
keyType = mapType.resolveGeneric(0);
|
||||||
|
valueType = mapType.resolveGeneric(1);
|
||||||
}
|
}
|
||||||
if (keyType != null || valueType != null) {
|
if (keyType != null || valueType != null) {
|
||||||
TypeConverter converter = getBeanTypeConverter();
|
TypeConverter converter = getBeanTypeConverter();
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,7 +21,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.TypeConverter;
|
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
|
* Simple factory for shared Set instances. Allows for central setup
|
||||||
@@ -86,7 +86,7 @@ public class SetFactoryBean extends AbstractFactoryBean<Set<Object>> {
|
|||||||
}
|
}
|
||||||
Class<?> valueType = null;
|
Class<?> valueType = null;
|
||||||
if (this.targetSetClass != null) {
|
if (this.targetSetClass != null) {
|
||||||
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetSetClass);
|
valueType = ResolvableType.forClass(this.targetSetClass).asCollection().resolveGeneric();
|
||||||
}
|
}
|
||||||
if (valueType != null) {
|
if (valueType != null) {
|
||||||
TypeConverter converter = getBeanTypeConverter();
|
TypeConverter converter = getBeanTypeConverter();
|
||||||
|
|||||||
@@ -1148,6 +1148,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
Class<?> type = descriptor.getDependencyType();
|
Class<?> type = descriptor.getDependencyType();
|
||||||
if (type.isArray()) {
|
if (type.isArray()) {
|
||||||
Class<?> componentType = type.getComponentType();
|
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,
|
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
|
||||||
new MultiElementDescriptor(descriptor));
|
new MultiElementDescriptor(descriptor));
|
||||||
if (matchingBeans.isEmpty()) {
|
if (matchingBeans.isEmpty()) {
|
||||||
@@ -1164,7 +1173,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
|
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
|
||||||
Class<?> elementType = descriptor.getCollectionType();
|
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
|
||||||
if (elementType == null) {
|
if (elementType == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1184,11 +1193,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else if (Map.class == type) {
|
else if (Map.class == type) {
|
||||||
Class<?> keyType = descriptor.getMapKeyType();
|
ResolvableType mapType = descriptor.getResolvableType().asMap();
|
||||||
|
Class<?> keyType = mapType.resolveGeneric(0);
|
||||||
if (String.class != keyType) {
|
if (String.class != keyType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Class<?> valueType = descriptor.getMapValueType();
|
Class<?> valueType = mapType.resolveGeneric(1);
|
||||||
if (valueType == null) {
|
if (valueType == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1592,12 +1592,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBean.class);
|
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBean.class);
|
||||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||||
bf.registerBeanDefinition("annotatedBean", bd);
|
bf.registerBeanDefinition("annotatedBean", bd);
|
||||||
|
String sv = "X";
|
||||||
|
bf.registerSingleton("stringValue", sv);
|
||||||
|
Integer iv = 1;
|
||||||
|
bf.registerSingleton("integerValue", iv);
|
||||||
StringRepository sr = new StringRepository();
|
StringRepository sr = new StringRepository();
|
||||||
bf.registerSingleton("stringRepo", sr);
|
bf.registerSingleton("stringRepo", sr);
|
||||||
IntegerRepository ir = new IntegerRepository();
|
IntegerRepository ir = new IntegerRepository();
|
||||||
bf.registerSingleton("integerRepo", ir);
|
bf.registerSingleton("integerRepo", ir);
|
||||||
|
|
||||||
RepositoryFieldInjectionBean bean = (RepositoryFieldInjectionBean) bf.getBean("annotatedBean");
|
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(sr, bean.stringRepository);
|
||||||
assertSame(ir, bean.integerRepository);
|
assertSame(ir, bean.integerRepository);
|
||||||
assertSame(1, bean.stringRepositoryArray.length);
|
assertSame(1, bean.stringRepositoryArray.length);
|
||||||
@@ -1624,12 +1642,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSubstitutedVariables.class);
|
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSubstitutedVariables.class);
|
||||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||||
bf.registerBeanDefinition("annotatedBean", bd);
|
bf.registerBeanDefinition("annotatedBean", bd);
|
||||||
|
String sv = "X";
|
||||||
|
bf.registerSingleton("stringValue", sv);
|
||||||
|
Integer iv = 1;
|
||||||
|
bf.registerSingleton("integerValue", iv);
|
||||||
StringRepository sr = new StringRepository();
|
StringRepository sr = new StringRepository();
|
||||||
bf.registerSingleton("stringRepo", sr);
|
bf.registerSingleton("stringRepo", sr);
|
||||||
IntegerRepository ir = new IntegerRepository();
|
IntegerRepository ir = new IntegerRepository();
|
||||||
bf.registerSingleton("integerRepo", ir);
|
bf.registerSingleton("integerRepo", ir);
|
||||||
|
|
||||||
RepositoryFieldInjectionBeanWithSubstitutedVariables bean = (RepositoryFieldInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
|
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(sr, bean.stringRepository);
|
||||||
assertSame(ir, bean.integerRepository);
|
assertSame(ir, bean.integerRepository);
|
||||||
assertSame(1, bean.stringRepositoryArray.length);
|
assertSame(1, bean.stringRepositoryArray.length);
|
||||||
@@ -1872,12 +1908,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBean.class);
|
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBean.class);
|
||||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||||
bf.registerBeanDefinition("annotatedBean", bd);
|
bf.registerBeanDefinition("annotatedBean", bd);
|
||||||
|
String sv = "X";
|
||||||
|
bf.registerSingleton("stringValue", sv);
|
||||||
|
Integer iv = 1;
|
||||||
|
bf.registerSingleton("integerValue", iv);
|
||||||
StringRepository sr = new StringRepository();
|
StringRepository sr = new StringRepository();
|
||||||
bf.registerSingleton("stringRepo", sr);
|
bf.registerSingleton("stringRepo", sr);
|
||||||
IntegerRepository ir = new IntegerRepository();
|
IntegerRepository ir = new IntegerRepository();
|
||||||
bf.registerSingleton("integerRepo", ir);
|
bf.registerSingleton("integerRepo", ir);
|
||||||
|
|
||||||
RepositoryMethodInjectionBean bean = (RepositoryMethodInjectionBean) bf.getBean("annotatedBean");
|
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(sr, bean.stringRepository);
|
||||||
assertSame(ir, bean.integerRepository);
|
assertSame(ir, bean.integerRepository);
|
||||||
assertSame(1, bean.stringRepositoryArray.length);
|
assertSame(1, bean.stringRepositoryArray.length);
|
||||||
@@ -1904,12 +1958,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBeanWithSubstitutedVariables.class);
|
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBeanWithSubstitutedVariables.class);
|
||||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||||
bf.registerBeanDefinition("annotatedBean", bd);
|
bf.registerBeanDefinition("annotatedBean", bd);
|
||||||
|
String sv = "X";
|
||||||
|
bf.registerSingleton("stringValue", sv);
|
||||||
|
Integer iv = 1;
|
||||||
|
bf.registerSingleton("integerValue", iv);
|
||||||
StringRepository sr = new StringRepository();
|
StringRepository sr = new StringRepository();
|
||||||
bf.registerSingleton("stringRepo", sr);
|
bf.registerSingleton("stringRepo", sr);
|
||||||
IntegerRepository ir = new IntegerRepository();
|
IntegerRepository ir = new IntegerRepository();
|
||||||
bf.registerSingleton("integerRepo", ir);
|
bf.registerSingleton("integerRepo", ir);
|
||||||
|
|
||||||
RepositoryMethodInjectionBeanWithSubstitutedVariables bean = (RepositoryMethodInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
|
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(sr, bean.stringRepository);
|
||||||
assertSame(ir, bean.integerRepository);
|
assertSame(ir, bean.integerRepository);
|
||||||
assertSame(1, bean.stringRepositoryArray.length);
|
assertSame(1, bean.stringRepositoryArray.length);
|
||||||
@@ -2968,6 +3040,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
|
|
||||||
public static class RepositoryFieldInjectionBean {
|
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
|
@Autowired
|
||||||
public Repository<String> stringRepository;
|
public Repository<String> stringRepository;
|
||||||
|
|
||||||
@@ -2996,6 +3092,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
|
|
||||||
public static class RepositoryFieldInjectionBeanWithVariables<S, I> {
|
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
|
@Autowired
|
||||||
public Repository<S> stringRepository;
|
public Repository<S> stringRepository;
|
||||||
|
|
||||||
@@ -3092,6 +3212,22 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
|
|
||||||
public static class RepositoryMethodInjectionBean {
|
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<String> stringRepository;
|
||||||
|
|
||||||
public Repository<Integer> integerRepository;
|
public Repository<Integer> integerRepository;
|
||||||
@@ -3108,6 +3244,46 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
|
|
||||||
public Map<String, Repository<Integer>> integerRepositoryMap;
|
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
|
@Autowired
|
||||||
public void setStringRepository(Repository<String> stringRepository) {
|
public void setStringRepository(Repository<String> stringRepository) {
|
||||||
this.stringRepository = stringRepository;
|
this.stringRepository = stringRepository;
|
||||||
@@ -3152,6 +3328,22 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
|
|
||||||
public static class RepositoryMethodInjectionBeanWithVariables<S, I> {
|
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<S> stringRepository;
|
||||||
|
|
||||||
public Repository<I> integerRepository;
|
public Repository<I> integerRepository;
|
||||||
@@ -3168,6 +3360,46 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
|
|
||||||
public Map<String, Repository<I>> integerRepositoryMap;
|
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
|
@Autowired
|
||||||
public void setStringRepository(Repository<S> stringRepository) {
|
public void setStringRepository(Repository<S> stringRepository) {
|
||||||
this.stringRepository = stringRepository;
|
this.stringRepository = stringRepository;
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -57,8 +57,8 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
|
|||||||
import org.springframework.beans.factory.DisposableBean;
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.core.CollectionFactory;
|
import org.springframework.core.CollectionFactory;
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.jmx.support.JmxUtils;
|
import org.springframework.jmx.support.JmxUtils;
|
||||||
import org.springframework.jmx.support.ObjectNameManager;
|
import org.springframework.jmx.support.ObjectNameManager;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
@@ -546,7 +546,8 @@ public class MBeanClientInterceptor
|
|||||||
return convertDataArrayToTargetArray(array, targetClass);
|
return convertDataArrayToTargetArray(array, targetClass);
|
||||||
}
|
}
|
||||||
else if (Collection.class.isAssignableFrom(targetClass)) {
|
else if (Collection.class.isAssignableFrom(targetClass)) {
|
||||||
Class<?> elementType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
|
Class<?> elementType =
|
||||||
|
ResolvableType.forMethodParameter(parameter).asCollection().resolveGeneric();
|
||||||
if (elementType != null) {
|
if (elementType != null) {
|
||||||
return convertDataArrayToTargetCollection(array, targetClass, elementType);
|
return convertDataArrayToTargetCollection(array, targetClass, elementType);
|
||||||
}
|
}
|
||||||
@@ -562,7 +563,8 @@ public class MBeanClientInterceptor
|
|||||||
return convertDataArrayToTargetArray(array, targetClass);
|
return convertDataArrayToTargetArray(array, targetClass);
|
||||||
}
|
}
|
||||||
else if (Collection.class.isAssignableFrom(targetClass)) {
|
else if (Collection.class.isAssignableFrom(targetClass)) {
|
||||||
Class<?> elementType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
|
Class<?> elementType =
|
||||||
|
ResolvableType.forMethodParameter(parameter).asCollection().resolveGeneric();
|
||||||
if (elementType != null) {
|
if (elementType != null) {
|
||||||
return convertDataArrayToTargetCollection(array, targetClass, elementType);
|
return convertDataArrayToTargetCollection(array, targetClass, elementType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -52,8 +52,8 @@ public abstract class Conventions {
|
|||||||
private static final Set<Class<?>> IGNORED_INTERFACES;
|
private static final Set<Class<?>> IGNORED_INTERFACES;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
IGNORED_INTERFACES = Collections.unmodifiableSet(new HashSet<Class<?>>(Arrays.<Class<?>>asList(
|
IGNORED_INTERFACES = Collections.unmodifiableSet(new HashSet<Class<?>>(
|
||||||
Serializable.class, Externalizable.class, Cloneable.class, Comparable.class)));
|
Arrays.<Class<?>>asList(Serializable.class, Externalizable.class, Cloneable.class, Comparable.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ public abstract class Conventions {
|
|||||||
pluralize = true;
|
pluralize = true;
|
||||||
}
|
}
|
||||||
else if (Collection.class.isAssignableFrom(parameter.getParameterType())) {
|
else if (Collection.class.isAssignableFrom(parameter.getParameterType())) {
|
||||||
valueClass = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
|
valueClass = ResolvableType.forMethodParameter(parameter).asCollection().resolveGeneric();
|
||||||
if (valueClass == null) {
|
if (valueClass == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Cannot generate variable name for non-typed Collection parameter type");
|
"Cannot generate variable name for non-typed Collection parameter type");
|
||||||
@@ -180,7 +180,7 @@ public abstract class Conventions {
|
|||||||
pluralize = true;
|
pluralize = true;
|
||||||
}
|
}
|
||||||
else if (Collection.class.isAssignableFrom(resolvedType)) {
|
else if (Collection.class.isAssignableFrom(resolvedType)) {
|
||||||
valueClass = GenericCollectionTypeResolver.getCollectionReturnType(method);
|
valueClass = ResolvableType.forMethodReturnType(method).asCollection().resolveGeneric();
|
||||||
if (valueClass == null) {
|
if (valueClass == null) {
|
||||||
if (!(value instanceof Collection)) {
|
if (!(value instanceof Collection)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -32,7 +32,9 @@ import java.util.Map;
|
|||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @see ResolvableType
|
* @see ResolvableType
|
||||||
|
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract class GenericCollectionTypeResolver {
|
public abstract class GenericCollectionTypeResolver {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -39,7 +39,6 @@ import org.springframework.util.ConcurrentReferenceHashMap;
|
|||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 2.5.2
|
* @since 2.5.2
|
||||||
* @see GenericCollectionTypeResolver
|
|
||||||
*/
|
*/
|
||||||
public abstract class GenericTypeResolver {
|
public abstract class GenericTypeResolver {
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -43,7 +43,6 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @see GenericCollectionTypeResolver
|
|
||||||
* @see org.springframework.core.annotation.SynthesizingMethodParameter
|
* @see org.springframework.core.annotation.SynthesizingMethodParameter
|
||||||
*/
|
*/
|
||||||
public class MethodParameter {
|
public class MethodParameter {
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -38,6 +38,7 @@ import static org.junit.Assert.*;
|
|||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class GenericCollectionTypeResolverTests {
|
public class GenericCollectionTypeResolverTests {
|
||||||
|
|
||||||
protected Class<?> targetClass;
|
protected Class<?> targetClass;
|
||||||
@@ -46,31 +47,15 @@ public class GenericCollectionTypeResolverTests {
|
|||||||
|
|
||||||
protected Type[] expectedResults;
|
protected Type[] expectedResults;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
this.targetClass = Foo.class;
|
this.targetClass = Foo.class;
|
||||||
this.methods = new String[] { "a", "b", "b2", "b3", "c", "d", "d2", "d3", "e",
|
this.methods = new String[] {"a", "b", "b2", "b3", "c", "d", "d2", "d3", "e", "e2", "e3"};
|
||||||
"e2", "e3" };
|
this.expectedResults = new Class<?>[] {Integer.class, null, Set.class, Set.class, null,
|
||||||
this.expectedResults = new Class[] { Integer.class, null, Set.class, Set.class,
|
Integer.class, Integer.class, Integer.class, Integer.class, Integer.class, Integer.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");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Type getType(Method method) {
|
|
||||||
return GenericCollectionTypeResolver.getMapValueReturnType(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void a() throws Exception {
|
public void a() throws Exception {
|
||||||
@@ -130,10 +115,8 @@ public class GenericCollectionTypeResolverTests {
|
|||||||
@Test
|
@Test
|
||||||
public void programmaticListIntrospection() throws Exception {
|
public void programmaticListIntrospection() throws Exception {
|
||||||
Method setter = GenericObject.class.getMethod("setResourceList", List.class);
|
Method setter = GenericObject.class.getMethod("setResourceList", List.class);
|
||||||
assertEquals(
|
assertEquals(Resource.class,
|
||||||
Resource.class,
|
GenericCollectionTypeResolver.getCollectionParameterType(new MethodParameter(setter, 0)));
|
||||||
GenericCollectionTypeResolver.getCollectionParameterType(new MethodParameter(
|
|
||||||
setter, 0)));
|
|
||||||
|
|
||||||
Method getter = GenericObject.class.getMethod("getResourceList");
|
Method getter = GenericObject.class.getMethod("getResourceList");
|
||||||
assertEquals(Resource.class,
|
assertEquals(Resource.class,
|
||||||
@@ -150,6 +133,24 @@ public class GenericCollectionTypeResolverTests {
|
|||||||
GenericCollectionTypeResolver.getMapValueType(CustomMap.class));
|
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> {
|
private static abstract class CustomSet<T> extends AbstractSet<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,8 +160,9 @@ public class GenericCollectionTypeResolverTests {
|
|||||||
private static abstract class OtherCustomMap<T> implements Map<String, Integer> {
|
private static abstract class OtherCustomMap<T> implements Map<String, Integer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static interface Foo {
|
private interface Foo {
|
||||||
|
|
||||||
Map<String, Integer> a();
|
Map<String, Integer> a();
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -22,8 +22,8 @@ import java.util.List;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.Part;
|
import javax.servlet.http.Part;
|
||||||
|
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.web.multipart.MultipartException;
|
import org.springframework.web.multipart.MultipartException;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@@ -155,7 +155,7 @@ public abstract class MultipartResolutionDelegate {
|
|||||||
private static Class<?> getCollectionParameterType(MethodParameter methodParam) {
|
private static Class<?> getCollectionParameterType(MethodParameter methodParam) {
|
||||||
Class<?> paramType = methodParam.getNestedParameterType();
|
Class<?> paramType = methodParam.getNestedParameterType();
|
||||||
if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){
|
if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){
|
||||||
Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
|
Class<?> valueType = ResolvableType.forMethodParameter(methodParam).asCollection().resolveGeneric();
|
||||||
if (valueType != null) {
|
if (valueType != null) {
|
||||||
return valueType;
|
return valueType;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user