Fixed hasUnresolvableGenerics() to return false in case of an unresolvable bounded variable as well
Issue: SPR-11250
This commit is contained in:
parent
bc3064cbb7
commit
f9e8eb59e1
|
@ -769,6 +769,21 @@ public class BeanFactoryGenericsTests {
|
|||
assertEquals(1, beans.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpr11250() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
|
||||
|
||||
bf.registerBeanDefinition("doubleStore", new RootBeanDefinition(NumberStore.class));
|
||||
bf.registerBeanDefinition("floatStore", new RootBeanDefinition(NumberStore.class));
|
||||
bf.registerBeanDefinition("numberBean",
|
||||
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
|
||||
|
||||
NumberBean nb = bf.getBean(NumberBean.class);
|
||||
assertNotNull(nb.getDoubleStore());
|
||||
assertNotNull(nb.getFloatStore());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NamedUrlList extends LinkedList<URL> {
|
||||
|
@ -831,4 +846,29 @@ public class BeanFactoryGenericsTests {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static class NumberStore<T extends Number> {
|
||||
}
|
||||
|
||||
|
||||
public static class NumberBean {
|
||||
|
||||
private final NumberStore<Double> doubleStore;
|
||||
|
||||
private final NumberStore<Float> floatStore;
|
||||
|
||||
public NumberBean(NumberStore<Double> doubleStore, NumberStore<Float> floatStore) {
|
||||
this.doubleStore = doubleStore;
|
||||
this.floatStore = floatStore;
|
||||
}
|
||||
|
||||
public NumberStore<Double> getDoubleStore() {
|
||||
return this.doubleStore;
|
||||
}
|
||||
|
||||
public NumberStore<Float> getFloatStore() {
|
||||
return this.floatStore;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -394,8 +394,12 @@ public final class ResolvableType implements Serializable {
|
|||
* The result will be {@code true} only in those two scenarios.
|
||||
*/
|
||||
public boolean hasUnresolvableGenerics() {
|
||||
for (Class<?> generic : resolveGenerics()) {
|
||||
if (generic == null) {
|
||||
if (this == NONE) {
|
||||
return false;
|
||||
}
|
||||
ResolvableType[] generics = getGenerics();
|
||||
for (ResolvableType generic : generics) {
|
||||
if (generic.isUnresolvableTypeVariable()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -408,8 +412,24 @@ public final class ResolvableType implements Serializable {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (resolved.getGenericSuperclass() != null) {
|
||||
return getSuperType().hasUnresolvableGenerics();
|
||||
return getSuperType().hasUnresolvableGenerics();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the underlying type is a type variable that
|
||||
* cannot be resolved through the associated variable resolver.
|
||||
*/
|
||||
private boolean isUnresolvableTypeVariable() {
|
||||
if (this.type instanceof TypeVariable) {
|
||||
if (this.variableResolver == null) {
|
||||
return true;
|
||||
}
|
||||
TypeVariable<?> variable = (TypeVariable<?>) this.type;
|
||||
ResolvableType resolved = this.variableResolver.resolveVariable(variable);
|
||||
if (resolved == null || resolved.isUnresolvableTypeVariable()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -486,11 +506,11 @@ public final class ResolvableType implements Serializable {
|
|||
if (indexes == null || indexes.length == 0) {
|
||||
return getGenerics()[0];
|
||||
}
|
||||
ResolvableType rtn = this;
|
||||
ResolvableType generic = this;
|
||||
for (int index : indexes) {
|
||||
rtn = rtn.getGenerics()[index];
|
||||
generic = generic.getGenerics()[index];
|
||||
}
|
||||
return rtn;
|
||||
return generic;
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
return NONE;
|
||||
|
|
|
@ -268,10 +268,16 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
|
||||
private GenericConverter.ConvertiblePair getRequiredTypeInfo(Object converter, Class<?> genericIfc) {
|
||||
ResolvableType resolvableType = ResolvableType.forClass(converter.getClass()).as(genericIfc);
|
||||
if(resolvableType.hasUnresolvableGenerics()) {
|
||||
ResolvableType[] generics = resolvableType.getGenerics();
|
||||
if (generics.length < 2) {
|
||||
return null;
|
||||
}
|
||||
return new GenericConverter.ConvertiblePair(resolvableType.resolveGeneric(0), resolvableType.resolveGeneric(1));
|
||||
Class<?> sourceType = generics[0].resolve();
|
||||
Class<?> targetType = generics[1].resolve();
|
||||
if (sourceType == null || targetType == null) {
|
||||
return null;
|
||||
}
|
||||
return new GenericConverter.ConvertiblePair(sourceType, targetType);
|
||||
}
|
||||
|
||||
private void invalidateCache() {
|
||||
|
@ -328,7 +334,7 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if(!this.typeInfo.getTargetType().equals(targetType.getObjectType())) {
|
||||
if (!this.typeInfo.getTargetType().equals(targetType.getObjectType())) {
|
||||
return false;
|
||||
}
|
||||
if (this.converter instanceof ConditionalConverter) {
|
||||
|
@ -382,9 +388,9 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
if (this.converterFactory instanceof ConditionalConverter) {
|
||||
matches = ((ConditionalConverter) this.converterFactory).matches(sourceType, targetType);
|
||||
}
|
||||
if(matches) {
|
||||
if (matches) {
|
||||
Converter<?, ?> converter = this.converterFactory.getConverter(targetType.getType());
|
||||
if(converter instanceof ConditionalConverter) {
|
||||
if (converter instanceof ConditionalConverter) {
|
||||
matches = ((ConditionalConverter) converter).matches(sourceType, targetType);
|
||||
}
|
||||
}
|
||||
|
@ -455,11 +461,10 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
*/
|
||||
private static class Converters {
|
||||
|
||||
private final Set<GenericConverter> globalConverters =
|
||||
new LinkedHashSet<GenericConverter>();
|
||||
private final Set<GenericConverter> globalConverters = new LinkedHashSet<GenericConverter>();
|
||||
|
||||
private final Map<ConvertiblePair, ConvertersForPair> converters =
|
||||
new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
|
||||
new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
|
||||
|
||||
public void add(GenericConverter converter) {
|
||||
Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
|
||||
|
@ -486,7 +491,7 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
}
|
||||
|
||||
public void remove(Class<?> sourceType, Class<?> targetType) {
|
||||
converters.remove(new ConvertiblePair(sourceType, targetType));
|
||||
this.converters.remove(new ConvertiblePair(sourceType, targetType));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -504,9 +509,8 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
for (Class<?> sourceCandidate : sourceCandidates) {
|
||||
for (Class<?> targetCandidate : targetCandidates) {
|
||||
ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
|
||||
GenericConverter converter = getRegisteredConverter(
|
||||
sourceType, targetType, convertiblePair);
|
||||
if(converter != null) {
|
||||
GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
|
@ -518,17 +522,17 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
TypeDescriptor targetType, ConvertiblePair convertiblePair) {
|
||||
|
||||
// Check specifically registered converters
|
||||
ConvertersForPair convertersForPair = converters.get(convertiblePair);
|
||||
GenericConverter converter = convertersForPair == null ? null
|
||||
: convertersForPair.getConverter(sourceType, targetType);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
|
||||
if (convertersForPair != null) {
|
||||
GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
|
||||
// Check ConditionalGenericConverter that match all types
|
||||
for (GenericConverter globalConverter : this.globalConverters) {
|
||||
if (((ConditionalConverter)globalConverter).matches(
|
||||
sourceType, targetType)) {
|
||||
if (((ConditionalConverter)globalConverter).matches(sourceType, targetType)) {
|
||||
return globalConverter;
|
||||
}
|
||||
}
|
||||
|
@ -568,10 +572,10 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
|
||||
private void addToClassHierarchy(int index, Class<?> type, boolean asArray,
|
||||
List<Class<?>> hierarchy, Set<Class<?>> visited) {
|
||||
if(asArray) {
|
||||
if (asArray) {
|
||||
type = Array.newInstance(type, 0).getClass();
|
||||
}
|
||||
if(visited.add(type)) {
|
||||
if (visited.add(type)) {
|
||||
hierarchy.add(index, type);
|
||||
}
|
||||
}
|
||||
|
@ -634,28 +638,26 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
*/
|
||||
private static class NoOpConverter implements GenericConverter {
|
||||
|
||||
private String name;
|
||||
|
||||
private final String name;
|
||||
|
||||
public NoOpConverter(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convert(Object source, TypeDescriptor sourceType,
|
||||
TypeDescriptor targetType) {
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue