Skip to content

Commit a60cb43

Browse files
author
Keith Donald
committed
added back element type checks in TypeDescriptor#isAssignable; clarified semantics in javadoc
1 parent 7dcd71c commit a60cb43

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,13 +279,30 @@ public Annotation getAnnotation(Class<? extends Annotation> annotationType) {
279279
}
280280

281281
/**
282-
* Returns true if an object of this type can be assigned to a reference of the given type.
283-
* @param typeDescriptor the descriptor for the target type
282+
* Returns true if an object of this type descriptor can be assigned to the location described by the given type descriptor.
283+
* For example, valueOf(String.class).isAssignableTo(valueOf(CharSequence.class)) returns true because a String value can be assigned to a CharSequence variable.
284+
* On the other hand, valueOf(Number.class).isAssignableTo(valueOf(Integer.class)) returns false because, while all Integers are Numbers, not all Numbers are Integers.
285+
* <p>
286+
* For arrays, collections, and maps, element and key/value types are checked if declared.
287+
* For example, a List&lt;String&gt; field value is assignable to a Collection&lt;CharSequence&gt; field, but List&lt;Number&gt; is not assignable to List&lt;Integer&gt;.
284288
* @return true if this type is assignable to the type represented by the provided type descriptor.
285289
* @see #getObjectType()
286290
*/
287291
public boolean isAssignableTo(TypeDescriptor typeDescriptor) {
288-
return typeDescriptor.getObjectType().isAssignableFrom(getObjectType());
292+
boolean typesAssignable = typeDescriptor.getObjectType().isAssignableFrom(getObjectType());
293+
if (!typesAssignable) {
294+
return false;
295+
}
296+
if (isArray()) {
297+
return getElementTypeDescriptor().isAssignableTo(typeDescriptor.getElementTypeDescriptor());
298+
} else if (isCollection()) {
299+
return isNestedAssignable(getElementTypeDescriptor(), typeDescriptor.getElementTypeDescriptor());
300+
} else if (isMap()) {
301+
return isNestedAssignable(getMapKeyTypeDescriptor(), typeDescriptor.getMapKeyTypeDescriptor()) &&
302+
isNestedAssignable(getMapValueTypeDescriptor(), typeDescriptor.getMapValueTypeDescriptor());
303+
} else {
304+
return true;
305+
}
289306
}
290307

291308
// indexable type descriptor operations
@@ -534,7 +551,14 @@ private TypeDescriptor narrow(Object value, TypeDescriptor typeDescriptor) {
534551
return value != null ? new TypeDescriptor(value.getClass(), null, null, null, annotations) : null;
535552
}
536553
}
537-
554+
555+
private boolean isNestedAssignable(TypeDescriptor nestedTypeDescriptor, TypeDescriptor otherNestedTypeDescriptor) {
556+
if (nestedTypeDescriptor == null || otherNestedTypeDescriptor == null) {
557+
return true;
558+
}
559+
return nestedTypeDescriptor.isAssignableTo(otherNestedTypeDescriptor);
560+
}
561+
538562
private String wildcard(TypeDescriptor typeDescriptor) {
539563
return typeDescriptor != null ? typeDescriptor.toString() : "?";
540564
}

org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ public void isAssignableTypes() {
759759
@Test
760760
public void isAssignableElementTypes() throws Exception {
761761
assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));
762-
assertTrue(new TypeDescriptor(getClass().getField("isAssignableElementTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));
762+
assertFalse(new TypeDescriptor(getClass().getField("isAssignableElementTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));
763763
assertTrue(TypeDescriptor.valueOf(List.class).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));
764764
}
765765

@@ -768,7 +768,7 @@ public void isAssignableElementTypes() throws Exception {
768768
@Test
769769
public void isAssignableMapKeyValueTypes() throws Exception {
770770
assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));
771-
assertTrue(new TypeDescriptor(getClass().getField("isAssignableMapKeyValueTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));
771+
assertFalse(new TypeDescriptor(getClass().getField("isAssignableMapKeyValueTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));
772772
assertTrue(TypeDescriptor.valueOf(Map.class).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));
773773
}
774774

0 commit comments

Comments
 (0)