Skip to content

Commit cb624e2

Browse files
committed
Fixed ExtendedBeanInfo and its tests to accept JDK 8 b117+ introspection results
Specifically, read and write methods are allowed to express property types with superclass/subclass relationships in both directions now. Issue: SPR-11139
1 parent 9281649 commit cb624e2

File tree

2 files changed

+60
-53
lines changed

2 files changed

+60
-53
lines changed

spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java

+58-47
Original file line numberDiff line numberDiff line change
@@ -209,37 +209,37 @@ public PropertyDescriptor[] getPropertyDescriptors() {
209209

210210
@Override
211211
public BeanInfo[] getAdditionalBeanInfo() {
212-
return delegate.getAdditionalBeanInfo();
212+
return this.delegate.getAdditionalBeanInfo();
213213
}
214214

215215
@Override
216216
public BeanDescriptor getBeanDescriptor() {
217-
return delegate.getBeanDescriptor();
217+
return this.delegate.getBeanDescriptor();
218218
}
219219

220220
@Override
221221
public int getDefaultEventIndex() {
222-
return delegate.getDefaultEventIndex();
222+
return this.delegate.getDefaultEventIndex();
223223
}
224224

225225
@Override
226226
public int getDefaultPropertyIndex() {
227-
return delegate.getDefaultPropertyIndex();
227+
return this.delegate.getDefaultPropertyIndex();
228228
}
229229

230230
@Override
231231
public EventSetDescriptor[] getEventSetDescriptors() {
232-
return delegate.getEventSetDescriptors();
232+
return this.delegate.getEventSetDescriptors();
233233
}
234234

235235
@Override
236236
public Image getIcon(int iconKind) {
237-
return delegate.getIcon(iconKind);
237+
return this.delegate.getIcon(iconKind);
238238
}
239239

240240
@Override
241241
public MethodDescriptor[] getMethodDescriptors() {
242-
return delegate.getMethodDescriptors();
242+
return this.delegate.getMethodDescriptors();
243243
}
244244
}
245245

@@ -293,7 +293,7 @@ public Class<?> getPropertyType() {
293293
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
294294
}
295295
catch (IntrospectionException ex) {
296-
// ignore, as does PropertyDescriptor#getPropertyType
296+
// Ignore, as does PropertyDescriptor#getPropertyType
297297
}
298298
}
299299
return this.propertyType;
@@ -383,7 +383,7 @@ public Class<?> getPropertyType() {
383383
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
384384
}
385385
catch (IntrospectionException ex) {
386-
// ignore, as does IndexedPropertyDescriptor#getPropertyType
386+
// Ignore, as does IndexedPropertyDescriptor#getPropertyType
387387
}
388388
}
389389
return this.propertyType;
@@ -417,7 +417,7 @@ public Class<?> getIndexedPropertyType() {
417417
getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
418418
}
419419
catch (IntrospectionException ex) {
420-
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
420+
// Ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
421421
}
422422
}
423423
return this.indexedPropertyType;
@@ -482,14 +482,14 @@ public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDe
482482
target.setShortDescription(source.getShortDescription());
483483
target.setDisplayName(source.getDisplayName());
484484

485-
// copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
485+
// Copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
486486
Enumeration<String> keys = source.attributeNames();
487487
while (keys.hasMoreElements()) {
488488
String key = keys.nextElement();
489489
target.setValue(key, source.getValue(key));
490490
}
491491

492-
// see java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
492+
// See java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
493493
target.setPropertyEditorClass(source.getPropertyEditorClass());
494494
target.setBound(source.isBound());
495495
target.setConstrained(source.isConstrained());
@@ -503,24 +503,34 @@ public static Class<?> findPropertyType(Method readMethod, Method writeMethod) t
503503
if (readMethod != null) {
504504
Class<?>[] params = readMethod.getParameterTypes();
505505
if (params.length != 0) {
506-
throw new IntrospectionException("bad read method arg count: " + readMethod);
506+
throw new IntrospectionException("Bad read method arg count: " + readMethod);
507507
}
508508
propertyType = readMethod.getReturnType();
509509
if (propertyType == Void.TYPE) {
510-
throw new IntrospectionException("read method "
511-
+ readMethod.getName() + " returns void");
510+
throw new IntrospectionException("Read method returns void: " + readMethod);
512511
}
513512
}
514513
if (writeMethod != null) {
515514
Class<?> params[] = writeMethod.getParameterTypes();
516515
if (params.length != 1) {
517-
throw new IntrospectionException("bad write method arg count: " + writeMethod);
516+
throw new IntrospectionException("Bad write method arg count: " + writeMethod);
518517
}
519-
if (propertyType != null
520-
&& !params[0].isAssignableFrom(propertyType)) {
521-
throw new IntrospectionException("type mismatch between read and write methods");
518+
if (propertyType != null) {
519+
if (propertyType.isAssignableFrom(params[0])) {
520+
// Write method's property type potentially more specific
521+
propertyType = params[0];
522+
}
523+
else if (params[0].isAssignableFrom(propertyType)) {
524+
// Proceed with read method's property type
525+
}
526+
else {
527+
throw new IntrospectionException(
528+
"Type mismatch between read and write methods: " + readMethod + " - " + writeMethod);
529+
}
530+
}
531+
else {
532+
propertyType = params[0];
522533
}
523-
propertyType = params[0];
524534
}
525535
return propertyType;
526536
}
@@ -532,44 +542,48 @@ public static Class<?> findIndexedPropertyType(String name, Class<?> propertyTyp
532542
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
533543

534544
Class<?> indexedPropertyType = null;
535-
536545
if (indexedReadMethod != null) {
537546
Class<?> params[] = indexedReadMethod.getParameterTypes();
538547
if (params.length != 1) {
539-
throw new IntrospectionException(
540-
"bad indexed read method arg count");
548+
throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
541549
}
542550
if (params[0] != Integer.TYPE) {
543-
throw new IntrospectionException(
544-
"non int index to indexed read method");
551+
throw new IntrospectionException("Non int index to indexed read method: " + indexedReadMethod);
545552
}
546553
indexedPropertyType = indexedReadMethod.getReturnType();
547554
if (indexedPropertyType == Void.TYPE) {
548-
throw new IntrospectionException(
549-
"indexed read method returns void");
555+
throw new IntrospectionException("Indexed read method returns void: " + indexedReadMethod);
550556
}
551557
}
552558
if (indexedWriteMethod != null) {
553559
Class<?> params[] = indexedWriteMethod.getParameterTypes();
554560
if (params.length != 2) {
555-
throw new IntrospectionException(
556-
"bad indexed write method arg count");
561+
throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
557562
}
558563
if (params[0] != Integer.TYPE) {
559-
throw new IntrospectionException(
560-
"non int index to indexed write method");
564+
throw new IntrospectionException("Non int index to indexed write method: " + indexedWriteMethod);
561565
}
562-
if (indexedPropertyType != null && indexedPropertyType != params[1]) {
563-
throw new IntrospectionException(
564-
"type mismatch between indexed read and indexed write methods: " + name);
566+
if (indexedPropertyType != null) {
567+
if (indexedPropertyType.isAssignableFrom(params[1])) {
568+
// Write method's property type potentially more specific
569+
indexedPropertyType = params[1];
570+
}
571+
else if (params[1].isAssignableFrom(indexedPropertyType)) {
572+
// Proceed with read method's property type
573+
}
574+
else {
575+
throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
576+
indexedReadMethod + " - " + indexedWriteMethod);
577+
}
578+
}
579+
else {
580+
indexedPropertyType = params[1];
565581
}
566-
indexedPropertyType = params[1];
567582
}
568-
if (propertyType != null
569-
&& (!propertyType.isArray() ||
570-
propertyType.getComponentType() != indexedPropertyType)) {
571-
throw new IntrospectionException(
572-
"type mismatch between indexed and non-indexed methods: " + name);
583+
if (propertyType != null && (!propertyType.isArray() ||
584+
propertyType.getComponentType() != indexedPropertyType)) {
585+
throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
586+
indexedReadMethod + " - " + indexedWriteMethod);
573587
}
574588
return indexedPropertyType;
575589
}
@@ -590,15 +604,12 @@ public static boolean equals(PropertyDescriptor pd1, Object obj) {
590604
if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) {
591605
return false;
592606
}
593-
594607
if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) {
595608
return false;
596609
}
597-
598-
if (pd1.getPropertyType() == pd2.getPropertyType()
599-
&& pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass()
600-
&& pd1.isBound() == pd2.isBound()
601-
&& pd1.isConstrained() == pd2.isConstrained()) {
610+
if (pd1.getPropertyType() == pd2.getPropertyType() &&
611+
pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass() &&
612+
pd1.isBound() == pd2.isBound() && pd1.isConstrained() == pd2.isConstrained()) {
602613
return true;
603614
}
604615
}
@@ -612,7 +623,7 @@ public static boolean compareMethods(Method a, Method b) {
612623
if ((a == null) != (b == null)) {
613624
return false;
614625
}
615-
if (a != null && b != null) {
626+
if (a != null) {
616627
if (!a.equals(b)) {
617628
return false;
618629
}

spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,8 @@ public void setFoo(Integer foo) { }
323323
BeanInfo ebi = new ExtendedBeanInfo(bi);
324324

325325
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
326-
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
327-
328326
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
329-
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
327+
assertEquals(hasWriteMethodForProperty(bi, "foo"), hasWriteMethodForProperty(ebi, "foo"));
330328
}
331329

332330
@Test
@@ -340,10 +338,8 @@ public void setFoos(int index, Integer foo) { }
340338
BeanInfo ebi = new ExtendedBeanInfo(bi);
341339

342340
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
343-
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
344-
345341
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
346-
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(false));
342+
assertEquals(hasIndexedWriteMethodForProperty(bi, "foos"), hasIndexedWriteMethodForProperty(ebi, "foos"));
347343
}
348344

349345
/**

0 commit comments

Comments
 (0)