Skip to content

Commit 5dc2d56

Browse files
committed
Fix regression with covariant property return types
Prior to this change, the Property class introduced in 3.1 M2 validated read/write property method pairs based on whether their parameter/return types were equal to one another. This precluded the valid possibility of read method that returns a subtype of the write method's parameter type, and represented a regression against 3.1 M1 and earlier versions. The implementation now uses isAssignableFrom rather than a straight equals check against the types. Issue: SPR-8432
1 parent cc81451 commit 5dc2d56

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ private MethodParameter resolveMethodParameter() {
133133
if (read == null && write == null) {
134134
throw new IllegalStateException("Property is neither readable nor writeable");
135135
}
136-
if (read != null && write != null && !read.getParameterType().equals(write.getParameterType())) {
137-
throw new IllegalStateException("Read and write parameter types are not the same");
136+
if (read != null && write != null && !write.getParameterType().isAssignableFrom(read.getParameterType())) {
137+
throw new IllegalStateException("Write parameter is not assignable from read parameter");
138138
}
139139
return read != null ? read : write;
140140
}

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ public void propertyGenericType() throws Exception {
226226
assertEquals(Integer.class, desc.getType());
227227
}
228228

229+
@Test
230+
public void propertyTypeCovariance() throws Exception {
231+
GenericType<Number> genericBean = new NumberType();
232+
Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty", null), genericBean.getClass().getMethod("setProperty", Number.class));
233+
TypeDescriptor desc = new TypeDescriptor(property);
234+
assertEquals(Integer.class, desc.getType());
235+
}
236+
229237
@Test
230238
public void propertyGenericTypeList() throws Exception {
231239
GenericType<Integer> genericBean = new IntegerType();
@@ -239,7 +247,7 @@ public interface GenericType<T> {
239247
T getProperty();
240248

241249
void setProperty(T t);
242-
250+
243251
List<T> getListProperty();
244252

245253
void setListProperty(List<T> t);
@@ -270,6 +278,23 @@ public void setListProperty(List<Integer> t) {
270278

271279
}
272280

281+
public class NumberType implements GenericType<Number> {
282+
283+
public Integer getProperty() {
284+
return null;
285+
}
286+
287+
public void setProperty(Number t) {
288+
}
289+
290+
public List<Number> getListProperty() {
291+
return null;
292+
}
293+
294+
public void setListProperty(List<Number> t) {
295+
}
296+
}
297+
273298
@Test
274299
public void propertyGenericClassList() throws Exception {
275300
IntegerClass genericBean = new IntegerClass();

0 commit comments

Comments
 (0)