parent
d4e8daaede
commit
7e67da8a26
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -144,12 +144,16 @@ public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCan
|
|||
if (cacheType) {
|
||||
rbd.targetType = targetType;
|
||||
}
|
||||
if (descriptor.fallbackMatchAllowed() &&
|
||||
(targetType.hasUnresolvableGenerics() || targetType.resolve() == Properties.class)) {
|
||||
if (descriptor.fallbackMatchAllowed()) {
|
||||
// Fallback matches allow unresolvable generics, e.g. plain HashMap to Map<String,String>;
|
||||
// and pragmatically also java.util.Properties to any Map (since despite formally being a
|
||||
// Map<Object,Object>, java.util.Properties is usually perceived as a Map<String,String>).
|
||||
return true;
|
||||
if (targetType.hasUnresolvableGenerics()) {
|
||||
return dependencyType.isAssignableFromResolvedPart(targetType);
|
||||
}
|
||||
else if (targetType.resolve() == Properties.class) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Full check for complex generic type match...
|
||||
return dependencyType.isAssignableFrom(targetType);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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,8 +32,8 @@ class Spr16179Tests {
|
|||
void repro() {
|
||||
try (AnnotationConfigApplicationContext bf = new AnnotationConfigApplicationContext(AssemblerConfig.class, AssemblerInjection.class)) {
|
||||
assertThat(bf.getBean(AssemblerInjection.class).assembler0).isSameAs(bf.getBean("someAssembler"));
|
||||
// assertNull(bf.getBean(AssemblerInjection.class).assembler1); TODO: accidental match
|
||||
// assertNull(bf.getBean(AssemblerInjection.class).assembler2);
|
||||
assertThat(bf.getBean(AssemblerInjection.class).assembler1).isNull();
|
||||
assertThat(bf.getBean(AssemblerInjection.class).assembler2).isSameAs(bf.getBean("pageAssembler"));
|
||||
assertThat(bf.getBean(AssemblerInjection.class).assembler3).isSameAs(bf.getBean("pageAssembler"));
|
||||
assertThat(bf.getBean(AssemblerInjection.class).assembler4).isSameAs(bf.getBean("pageAssembler"));
|
||||
assertThat(bf.getBean(AssemblerInjection.class).assembler5).isSameAs(bf.getBean("pageAssembler"));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -265,7 +265,7 @@ public class ResolvableType implements Serializable {
|
|||
public boolean isAssignableFrom(Class<?> other) {
|
||||
// As of 6.1: shortcut assignability check for top-level Class references
|
||||
return (this.type instanceof Class<?> clazz ? ClassUtils.isAssignable(clazz, other) :
|
||||
isAssignableFrom(forClass(other), false, null));
|
||||
isAssignableFrom(forClass(other), false, null, false));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -280,10 +280,24 @@ public class ResolvableType implements Serializable {
|
|||
* {@code ResolvableType}; {@code false} otherwise
|
||||
*/
|
||||
public boolean isAssignableFrom(ResolvableType other) {
|
||||
return isAssignableFrom(other, false, null);
|
||||
return isAssignableFrom(other, false, null, false);
|
||||
}
|
||||
|
||||
private boolean isAssignableFrom(ResolvableType other, boolean strict, @Nullable Map<Type, Type> matchedBefore) {
|
||||
/**
|
||||
* Determine whether this {@code ResolvableType} is assignable from the
|
||||
* specified other type, as far as the other type is actually resolvable.
|
||||
* @param other the type to be checked against (as a {@code ResolvableType})
|
||||
* @return {@code true} if the specified other type can be assigned to this
|
||||
* {@code ResolvableType} as far as it is resolvable; {@code false} otherwise
|
||||
* @since 6.2
|
||||
*/
|
||||
public boolean isAssignableFromResolvedPart(ResolvableType other) {
|
||||
return isAssignableFrom(other, false, null, true);
|
||||
}
|
||||
|
||||
private boolean isAssignableFrom(ResolvableType other, boolean strict,
|
||||
@Nullable Map<Type, Type> matchedBefore, boolean upUntilUnresolvable) {
|
||||
|
||||
Assert.notNull(other, "ResolvableType must not be null");
|
||||
|
||||
// If we cannot resolve types, we are not assignable
|
||||
|
@ -305,7 +319,12 @@ public class ResolvableType implements Serializable {
|
|||
|
||||
// Deal with array by delegating to the component type
|
||||
if (isArray()) {
|
||||
return (other.isArray() && getComponentType().isAssignableFrom(other.getComponentType(), true, matchedBefore));
|
||||
return (other.isArray() && getComponentType().isAssignableFrom(
|
||||
other.getComponentType(), true, matchedBefore, upUntilUnresolvable));
|
||||
}
|
||||
|
||||
if (upUntilUnresolvable && other.isUnresolvableTypeVariable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deal with wildcard bounds
|
||||
|
@ -314,8 +333,15 @@ public class ResolvableType implements Serializable {
|
|||
|
||||
// In the form X is assignable to <? extends Number>
|
||||
if (typeBounds != null) {
|
||||
return (ourBounds != null && ourBounds.isSameKind(typeBounds) &&
|
||||
ourBounds.isAssignableFrom(typeBounds.getBounds()));
|
||||
if (ourBounds != null) {
|
||||
return (ourBounds.isSameKind(typeBounds) && ourBounds.isAssignableFrom(typeBounds.getBounds()));
|
||||
}
|
||||
else if (upUntilUnresolvable) {
|
||||
return typeBounds.isAssignableFrom(this);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// In the form <? extends Number> is assignable to X...
|
||||
|
@ -376,7 +402,7 @@ public class ResolvableType implements Serializable {
|
|||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], true, matchedBefore)) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], true, matchedBefore, upUntilUnresolvable)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue