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
This commit is contained in:
Juergen Hoeller 2013-12-10 22:34:17 +01:00
parent 92816492ed
commit cb624e25c5
2 changed files with 60 additions and 53 deletions

View File

@ -209,37 +209,37 @@ class ExtendedBeanInfo implements BeanInfo {
@Override @Override
public BeanInfo[] getAdditionalBeanInfo() { public BeanInfo[] getAdditionalBeanInfo() {
return delegate.getAdditionalBeanInfo(); return this.delegate.getAdditionalBeanInfo();
} }
@Override @Override
public BeanDescriptor getBeanDescriptor() { public BeanDescriptor getBeanDescriptor() {
return delegate.getBeanDescriptor(); return this.delegate.getBeanDescriptor();
} }
@Override @Override
public int getDefaultEventIndex() { public int getDefaultEventIndex() {
return delegate.getDefaultEventIndex(); return this.delegate.getDefaultEventIndex();
} }
@Override @Override
public int getDefaultPropertyIndex() { public int getDefaultPropertyIndex() {
return delegate.getDefaultPropertyIndex(); return this.delegate.getDefaultPropertyIndex();
} }
@Override @Override
public EventSetDescriptor[] getEventSetDescriptors() { public EventSetDescriptor[] getEventSetDescriptors() {
return delegate.getEventSetDescriptors(); return this.delegate.getEventSetDescriptors();
} }
@Override @Override
public Image getIcon(int iconKind) { public Image getIcon(int iconKind) {
return delegate.getIcon(iconKind); return this.delegate.getIcon(iconKind);
} }
@Override @Override
public MethodDescriptor[] getMethodDescriptors() { public MethodDescriptor[] getMethodDescriptors() {
return delegate.getMethodDescriptors(); return this.delegate.getMethodDescriptors();
} }
} }
@ -293,7 +293,7 @@ class SimplePropertyDescriptor extends PropertyDescriptor {
this.propertyType = findPropertyType(this.readMethod, this.writeMethod); this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
} }
catch (IntrospectionException ex) { catch (IntrospectionException ex) {
// ignore, as does PropertyDescriptor#getPropertyType // Ignore, as does PropertyDescriptor#getPropertyType
} }
} }
return this.propertyType; return this.propertyType;
@ -383,7 +383,7 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
this.propertyType = findPropertyType(this.readMethod, this.writeMethod); this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
} }
catch (IntrospectionException ex) { catch (IntrospectionException ex) {
// ignore, as does IndexedPropertyDescriptor#getPropertyType // Ignore, as does IndexedPropertyDescriptor#getPropertyType
} }
} }
return this.propertyType; return this.propertyType;
@ -417,7 +417,7 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod); getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
} }
catch (IntrospectionException ex) { catch (IntrospectionException ex) {
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType // Ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
} }
} }
return this.indexedPropertyType; return this.indexedPropertyType;
@ -482,14 +482,14 @@ class PropertyDescriptorUtils {
target.setShortDescription(source.getShortDescription()); target.setShortDescription(source.getShortDescription());
target.setDisplayName(source.getDisplayName()); target.setDisplayName(source.getDisplayName());
// copy all attributes (emulating behavior of private FeatureDescriptor#addTable) // Copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
Enumeration<String> keys = source.attributeNames(); Enumeration<String> keys = source.attributeNames();
while (keys.hasMoreElements()) { while (keys.hasMoreElements()) {
String key = keys.nextElement(); String key = keys.nextElement();
target.setValue(key, source.getValue(key)); target.setValue(key, source.getValue(key));
} }
// see java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor) // See java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
target.setPropertyEditorClass(source.getPropertyEditorClass()); target.setPropertyEditorClass(source.getPropertyEditorClass());
target.setBound(source.isBound()); target.setBound(source.isBound());
target.setConstrained(source.isConstrained()); target.setConstrained(source.isConstrained());
@ -503,24 +503,34 @@ class PropertyDescriptorUtils {
if (readMethod != null) { if (readMethod != null) {
Class<?>[] params = readMethod.getParameterTypes(); Class<?>[] params = readMethod.getParameterTypes();
if (params.length != 0) { if (params.length != 0) {
throw new IntrospectionException("bad read method arg count: " + readMethod); throw new IntrospectionException("Bad read method arg count: " + readMethod);
} }
propertyType = readMethod.getReturnType(); propertyType = readMethod.getReturnType();
if (propertyType == Void.TYPE) { if (propertyType == Void.TYPE) {
throw new IntrospectionException("read method " throw new IntrospectionException("Read method returns void: " + readMethod);
+ readMethod.getName() + " returns void");
} }
} }
if (writeMethod != null) { if (writeMethod != null) {
Class<?> params[] = writeMethod.getParameterTypes(); Class<?> params[] = writeMethod.getParameterTypes();
if (params.length != 1) { if (params.length != 1) {
throw new IntrospectionException("bad write method arg count: " + writeMethod); throw new IntrospectionException("Bad write method arg count: " + writeMethod);
} }
if (propertyType != null if (propertyType != null) {
&& !params[0].isAssignableFrom(propertyType)) { if (propertyType.isAssignableFrom(params[0])) {
throw new IntrospectionException("type mismatch between read and write methods"); // Write method's property type potentially more specific
propertyType = params[0];
}
else if (params[0].isAssignableFrom(propertyType)) {
// Proceed with read method's property type
}
else {
throw new IntrospectionException(
"Type mismatch between read and write methods: " + readMethod + " - " + writeMethod);
}
}
else {
propertyType = params[0];
} }
propertyType = params[0];
} }
return propertyType; return propertyType;
} }
@ -532,44 +542,48 @@ class PropertyDescriptorUtils {
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException { Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
Class<?> indexedPropertyType = null; Class<?> indexedPropertyType = null;
if (indexedReadMethod != null) { if (indexedReadMethod != null) {
Class<?> params[] = indexedReadMethod.getParameterTypes(); Class<?> params[] = indexedReadMethod.getParameterTypes();
if (params.length != 1) { if (params.length != 1) {
throw new IntrospectionException( throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
"bad indexed read method arg count");
} }
if (params[0] != Integer.TYPE) { if (params[0] != Integer.TYPE) {
throw new IntrospectionException( throw new IntrospectionException("Non int index to indexed read method: " + indexedReadMethod);
"non int index to indexed read method");
} }
indexedPropertyType = indexedReadMethod.getReturnType(); indexedPropertyType = indexedReadMethod.getReturnType();
if (indexedPropertyType == Void.TYPE) { if (indexedPropertyType == Void.TYPE) {
throw new IntrospectionException( throw new IntrospectionException("Indexed read method returns void: " + indexedReadMethod);
"indexed read method returns void");
} }
} }
if (indexedWriteMethod != null) { if (indexedWriteMethod != null) {
Class<?> params[] = indexedWriteMethod.getParameterTypes(); Class<?> params[] = indexedWriteMethod.getParameterTypes();
if (params.length != 2) { if (params.length != 2) {
throw new IntrospectionException( throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
"bad indexed write method arg count");
} }
if (params[0] != Integer.TYPE) { if (params[0] != Integer.TYPE) {
throw new IntrospectionException( throw new IntrospectionException("Non int index to indexed write method: " + indexedWriteMethod);
"non int index to indexed write method");
} }
if (indexedPropertyType != null && indexedPropertyType != params[1]) { if (indexedPropertyType != null) {
throw new IntrospectionException( if (indexedPropertyType.isAssignableFrom(params[1])) {
"type mismatch between indexed read and indexed write methods: " + name); // Write method's property type potentially more specific
indexedPropertyType = params[1];
}
else if (params[1].isAssignableFrom(indexedPropertyType)) {
// Proceed with read method's property type
}
else {
throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
indexedReadMethod + " - " + indexedWriteMethod);
}
}
else {
indexedPropertyType = params[1];
} }
indexedPropertyType = params[1];
} }
if (propertyType != null if (propertyType != null && (!propertyType.isArray() ||
&& (!propertyType.isArray() || propertyType.getComponentType() != indexedPropertyType)) {
propertyType.getComponentType() != indexedPropertyType)) { throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
throw new IntrospectionException( indexedReadMethod + " - " + indexedWriteMethod);
"type mismatch between indexed and non-indexed methods: " + name);
} }
return indexedPropertyType; return indexedPropertyType;
} }
@ -590,15 +604,12 @@ class PropertyDescriptorUtils {
if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) { if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) {
return false; return false;
} }
if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) { if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) {
return false; return false;
} }
if (pd1.getPropertyType() == pd2.getPropertyType() &&
if (pd1.getPropertyType() == pd2.getPropertyType() pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass() &&
&& pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass() pd1.isBound() == pd2.isBound() && pd1.isConstrained() == pd2.isConstrained()) {
&& pd1.isBound() == pd2.isBound()
&& pd1.isConstrained() == pd2.isConstrained()) {
return true; return true;
} }
} }
@ -612,7 +623,7 @@ class PropertyDescriptorUtils {
if ((a == null) != (b == null)) { if ((a == null) != (b == null)) {
return false; return false;
} }
if (a != null && b != null) { if (a != null) {
if (!a.equals(b)) { if (!a.equals(b)) {
return false; return false;
} }

View File

@ -323,10 +323,8 @@ public class ExtendedBeanInfoTests {
BeanInfo ebi = new ExtendedBeanInfo(bi); BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true)); assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true)); assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false)); assertEquals(hasWriteMethodForProperty(bi, "foo"), hasWriteMethodForProperty(ebi, "foo"));
} }
@Test @Test
@ -340,10 +338,8 @@ public class ExtendedBeanInfoTests {
BeanInfo ebi = new ExtendedBeanInfo(bi); BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true)); assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true)); assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(false)); assertEquals(hasIndexedWriteMethodForProperty(bi, "foos"), hasIndexedWriteMethodForProperty(ebi, "foos"));
} }
/** /**