Fix ResolvableType isAssignableFrom for <?>
Fix ResolvableType.isAssignableFrom to correctly deal with <?> style generics. Issue: SPR-10973
This commit is contained in:
parent
501a1cbb5d
commit
5358cc0f5f
|
@ -138,7 +138,7 @@ public final class ResolvableType implements TypeVariableResolver {
|
||||||
Assert.notNull(type, "Type must not be null");
|
Assert.notNull(type, "Type must not be null");
|
||||||
|
|
||||||
// If we cannot resolve types, we are not assignable
|
// If we cannot resolve types, we are not assignable
|
||||||
if (resolve() == null || type.resolve() == null) {
|
if (this == NONE || type == NONE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,15 +164,16 @@ public final class ResolvableType implements TypeVariableResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main assignability check
|
// Main assignability check
|
||||||
boolean rtn = resolve().isAssignableFrom(type.resolve());
|
boolean rtn = resolve(Object.class).isAssignableFrom(type.resolve(Object.class));
|
||||||
|
|
||||||
// We need an exact type match for generics
|
// We need an exact type match for generics
|
||||||
// List<CharSequence> is not assignable from List<String>
|
// List<CharSequence> is not assignable from List<String>
|
||||||
rtn &= (!checkingGeneric || resolve().equals(type.resolve()));
|
rtn &= (!checkingGeneric || resolve(Object.class).equals(type.resolve(Object.class)));
|
||||||
|
|
||||||
// Recursively check each generic
|
// Recursively check each generic
|
||||||
for (int i = 0; i < getGenerics().length; i++) {
|
for (int i = 0; i < getGenerics().length; i++) {
|
||||||
rtn &= getGeneric(i).isAssignableFrom(type.as(resolve()).getGeneric(i), true);
|
rtn &= getGeneric(i).isAssignableFrom(
|
||||||
|
type.as(resolve(Object.class)).getGeneric(i), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtn;
|
return rtn;
|
||||||
|
|
|
@ -52,8 +52,6 @@ import static org.mockito.BDDMockito.*;
|
||||||
import static org.mockito.Matchers.*;
|
import static org.mockito.Matchers.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
// FIXME nested
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ResolvableType}.
|
* Tests for {@link ResolvableType}.
|
||||||
*
|
*
|
||||||
|
@ -822,8 +820,8 @@ public class ResolvableTypeTests {
|
||||||
ResolvableType objectType = ResolvableType.forClass(Object.class);
|
ResolvableType objectType = ResolvableType.forClass(Object.class);
|
||||||
ResolvableType unresolvableVariable = ResolvableType.forField(AssignmentBase.class.getField("o"));
|
ResolvableType unresolvableVariable = ResolvableType.forField(AssignmentBase.class.getField("o"));
|
||||||
assertThat(unresolvableVariable.resolve(), nullValue());
|
assertThat(unresolvableVariable.resolve(), nullValue());
|
||||||
assertAssignable(objectType, unresolvableVariable).equalTo(false);
|
assertAssignable(objectType, unresolvableVariable).equalTo(true);
|
||||||
assertAssignable(unresolvableVariable, objectType).equalTo(false);
|
assertAssignable(unresolvableVariable, objectType).equalTo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -936,6 +934,7 @@ public class ResolvableTypeTests {
|
||||||
ResolvableType object = ResolvableType.forClass(Object.class);
|
ResolvableType object = ResolvableType.forClass(Object.class);
|
||||||
ResolvableType charSequence = ResolvableType.forClass(CharSequence.class);
|
ResolvableType charSequence = ResolvableType.forClass(CharSequence.class);
|
||||||
ResolvableType string = ResolvableType.forClass(String.class);
|
ResolvableType string = ResolvableType.forClass(String.class);
|
||||||
|
ResolvableType extendsAnon = ResolvableType.forField(AssignmentBase.class.getField("listAnon"), Assignment.class).getGeneric();
|
||||||
ResolvableType extendsObject = ResolvableType.forField(AssignmentBase.class.getField("listxo"), Assignment.class).getGeneric();
|
ResolvableType extendsObject = ResolvableType.forField(AssignmentBase.class.getField("listxo"), Assignment.class).getGeneric();
|
||||||
ResolvableType extendsCharSequence = ResolvableType.forField(AssignmentBase.class.getField("listxc"), Assignment.class).getGeneric();
|
ResolvableType extendsCharSequence = ResolvableType.forField(AssignmentBase.class.getField("listxc"), Assignment.class).getGeneric();
|
||||||
ResolvableType extendsString = ResolvableType.forField(AssignmentBase.class.getField("listxs"), Assignment.class).getGeneric();
|
ResolvableType extendsString = ResolvableType.forField(AssignmentBase.class.getField("listxs"), Assignment.class).getGeneric();
|
||||||
|
@ -972,6 +971,8 @@ public class ResolvableTypeTests {
|
||||||
equalTo(false, true, true);
|
equalTo(false, true, true);
|
||||||
assertAssignable(charSequence, extendsObject, extendsCharSequence, extendsString).
|
assertAssignable(charSequence, extendsObject, extendsCharSequence, extendsString).
|
||||||
equalTo(false, false, false);
|
equalTo(false, false, false);
|
||||||
|
assertAssignable(extendsAnon, object, charSequence, string).
|
||||||
|
equalTo(true, true, true);
|
||||||
|
|
||||||
// T <= ? super T
|
// T <= ? super T
|
||||||
assertAssignable(superCharSequence, object, charSequence, string).
|
assertAssignable(superCharSequence, object, charSequence, string).
|
||||||
|
@ -1144,6 +1145,8 @@ public class ResolvableTypeTests {
|
||||||
|
|
||||||
public List<S> lists;
|
public List<S> lists;
|
||||||
|
|
||||||
|
public List<?> listAnon;
|
||||||
|
|
||||||
public List<? extends O> listxo;
|
public List<? extends O> listxo;
|
||||||
|
|
||||||
public List<? extends C> listxc;
|
public List<? extends C> listxc;
|
||||||
|
|
Loading…
Reference in New Issue