Skip to content

Commit 8827263

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 (cherry picked from commit cb624e2)
1 parent 2e15f94 commit 8827263

File tree

2 files changed

+116
-113
lines changed

2 files changed

+116
-113
lines changed

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

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
4242
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
4343
* and/or non-void returning setter methods. For example:
44-
* <pre>{@code
44+
* <pre class="code">
4545
* public class Bean {
4646
* private Foo foo;
4747
*
@@ -53,7 +53,7 @@
5353
* this.foo = foo;
5454
* return this;
5555
* }
56-
* }}</pre>
56+
* }</pre>
5757
* The standard JavaBeans {@code Introspector} will discover the {@code getFoo} read
5858
* method, but will bypass the {@code #setFoo(Foo)} write method, because its non-void
5959
* returning signature does not comply with the JavaBeans specification.
@@ -206,31 +206,31 @@ public PropertyDescriptor[] getPropertyDescriptors() {
206206
}
207207

208208
public BeanInfo[] getAdditionalBeanInfo() {
209-
return delegate.getAdditionalBeanInfo();
209+
return this.delegate.getAdditionalBeanInfo();
210210
}
211211

212212
public BeanDescriptor getBeanDescriptor() {
213-
return delegate.getBeanDescriptor();
213+
return this.delegate.getBeanDescriptor();
214214
}
215215

216216
public int getDefaultEventIndex() {
217-
return delegate.getDefaultEventIndex();
217+
return this.delegate.getDefaultEventIndex();
218218
}
219219

220220
public int getDefaultPropertyIndex() {
221-
return delegate.getDefaultPropertyIndex();
221+
return this.delegate.getDefaultPropertyIndex();
222222
}
223223

224224
public EventSetDescriptor[] getEventSetDescriptors() {
225-
return delegate.getEventSetDescriptors();
225+
return this.delegate.getEventSetDescriptors();
226226
}
227227

228228
public Image getIcon(int iconKind) {
229-
return delegate.getIcon(iconKind);
229+
return this.delegate.getIcon(iconKind);
230230
}
231231

232232
public MethodDescriptor[] getMethodDescriptors() {
233-
return delegate.getMethodDescriptors();
233+
return this.delegate.getMethodDescriptors();
234234
}
235235
}
236236

@@ -284,7 +284,7 @@ public Class<?> getPropertyType() {
284284
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
285285
}
286286
catch (IntrospectionException ex) {
287-
// ignore, as does PropertyDescriptor#getPropertyType
287+
// Ignore, as does PropertyDescriptor#getPropertyType
288288
}
289289
}
290290
return this.propertyType;
@@ -374,7 +374,7 @@ public Class<?> getPropertyType() {
374374
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
375375
}
376376
catch (IntrospectionException ex) {
377-
// ignore, as does IndexedPropertyDescriptor#getPropertyType
377+
// Ignore, as does IndexedPropertyDescriptor#getPropertyType
378378
}
379379
}
380380
return this.propertyType;
@@ -408,7 +408,7 @@ public Class<?> getIndexedPropertyType() {
408408
getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
409409
}
410410
catch (IntrospectionException ex) {
411-
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
411+
// Ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
412412
}
413413
}
414414
return this.indexedPropertyType;
@@ -473,14 +473,14 @@ public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDe
473473
target.setShortDescription(source.getShortDescription());
474474
target.setDisplayName(source.getDisplayName());
475475

476-
// copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
476+
// Copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
477477
Enumeration<String> keys = source.attributeNames();
478478
while (keys.hasMoreElements()) {
479479
String key = keys.nextElement();
480480
target.setValue(key, source.getValue(key));
481481
}
482482

483-
// see java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
483+
// See java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
484484
target.setPropertyEditorClass(source.getPropertyEditorClass());
485485
target.setBound(source.isBound());
486486
target.setConstrained(source.isConstrained());
@@ -494,24 +494,34 @@ public static Class<?> findPropertyType(Method readMethod, Method writeMethod) t
494494
if (readMethod != null) {
495495
Class<?>[] params = readMethod.getParameterTypes();
496496
if (params.length != 0) {
497-
throw new IntrospectionException("bad read method arg count: " + readMethod);
497+
throw new IntrospectionException("Bad read method arg count: " + readMethod);
498498
}
499499
propertyType = readMethod.getReturnType();
500500
if (propertyType == Void.TYPE) {
501-
throw new IntrospectionException("read method "
502-
+ readMethod.getName() + " returns void");
501+
throw new IntrospectionException("Read method returns void: " + readMethod);
503502
}
504503
}
505504
if (writeMethod != null) {
506505
Class<?> params[] = writeMethod.getParameterTypes();
507506
if (params.length != 1) {
508-
throw new IntrospectionException("bad write method arg count: " + writeMethod);
507+
throw new IntrospectionException("Bad write method arg count: " + writeMethod);
509508
}
510-
if (propertyType != null
511-
&& !params[0].isAssignableFrom(propertyType)) {
512-
throw new IntrospectionException("type mismatch between read and write methods");
509+
if (propertyType != null) {
510+
if (propertyType.isAssignableFrom(params[0])) {
511+
// Write method's property type potentially more specific
512+
propertyType = params[0];
513+
}
514+
else if (params[0].isAssignableFrom(propertyType)) {
515+
// Proceed with read method's property type
516+
}
517+
else {
518+
throw new IntrospectionException(
519+
"Type mismatch between read and write methods: " + readMethod + " - " + writeMethod);
520+
}
521+
}
522+
else {
523+
propertyType = params[0];
513524
}
514-
propertyType = params[0];
515525
}
516526
return propertyType;
517527
}
@@ -523,44 +533,48 @@ public static Class<?> findIndexedPropertyType(String name, Class<?> propertyTyp
523533
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
524534

525535
Class<?> indexedPropertyType = null;
526-
527536
if (indexedReadMethod != null) {
528537
Class<?> params[] = indexedReadMethod.getParameterTypes();
529538
if (params.length != 1) {
530-
throw new IntrospectionException(
531-
"bad indexed read method arg count");
539+
throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
532540
}
533541
if (params[0] != Integer.TYPE) {
534-
throw new IntrospectionException(
535-
"non int index to indexed read method");
542+
throw new IntrospectionException("Non int index to indexed read method: " + indexedReadMethod);
536543
}
537544
indexedPropertyType = indexedReadMethod.getReturnType();
538545
if (indexedPropertyType == Void.TYPE) {
539-
throw new IntrospectionException(
540-
"indexed read method returns void");
546+
throw new IntrospectionException("Indexed read method returns void: " + indexedReadMethod);
541547
}
542548
}
543549
if (indexedWriteMethod != null) {
544550
Class<?> params[] = indexedWriteMethod.getParameterTypes();
545551
if (params.length != 2) {
546-
throw new IntrospectionException(
547-
"bad indexed write method arg count");
552+
throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
548553
}
549554
if (params[0] != Integer.TYPE) {
550-
throw new IntrospectionException(
551-
"non int index to indexed write method");
555+
throw new IntrospectionException("Non int index to indexed write method: " + indexedWriteMethod);
552556
}
553-
if (indexedPropertyType != null && indexedPropertyType != params[1]) {
554-
throw new IntrospectionException(
555-
"type mismatch between indexed read and indexed write methods: " + name);
557+
if (indexedPropertyType != null) {
558+
if (indexedPropertyType.isAssignableFrom(params[1])) {
559+
// Write method's property type potentially more specific
560+
indexedPropertyType = params[1];
561+
}
562+
else if (params[1].isAssignableFrom(indexedPropertyType)) {
563+
// Proceed with read method's property type
564+
}
565+
else {
566+
throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
567+
indexedReadMethod + " - " + indexedWriteMethod);
568+
}
569+
}
570+
else {
571+
indexedPropertyType = params[1];
556572
}
557-
indexedPropertyType = params[1];
558573
}
559-
if (propertyType != null
560-
&& (!propertyType.isArray() ||
561-
propertyType.getComponentType() != indexedPropertyType)) {
562-
throw new IntrospectionException(
563-
"type mismatch between indexed and non-indexed methods: " + name);
574+
if (propertyType != null && (!propertyType.isArray() ||
575+
propertyType.getComponentType() != indexedPropertyType)) {
576+
throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
577+
indexedReadMethod + " - " + indexedWriteMethod);
564578
}
565579
return indexedPropertyType;
566580
}
@@ -581,15 +595,12 @@ public static boolean equals(PropertyDescriptor pd1, Object obj) {
581595
if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) {
582596
return false;
583597
}
584-
585598
if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) {
586599
return false;
587600
}
588-
589-
if (pd1.getPropertyType() == pd2.getPropertyType()
590-
&& pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass()
591-
&& pd1.isBound() == pd2.isBound()
592-
&& pd1.isConstrained() == pd2.isConstrained()) {
601+
if (pd1.getPropertyType() == pd2.getPropertyType() &&
602+
pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass() &&
603+
pd1.isBound() == pd2.isBound() && pd1.isConstrained() == pd2.isConstrained()) {
593604
return true;
594605
}
595606
}
@@ -603,7 +614,7 @@ public static boolean compareMethods(Method a, Method b) {
603614
if ((a == null) != (b == null)) {
604615
return false;
605616
}
606-
if (a != null && b != null) {
617+
if (a != null) {
607618
if (!a.equals(b)) {
608619
return false;
609620
}

0 commit comments

Comments
 (0)