From e5231526536f0ea904264dca80416c7f9f9f9c2c Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 2 Sep 2013 16:42:06 +0200 Subject: [PATCH] Properly handle getMethodDescriptors() null value on IBM JVM Also internally renaming SimpleNonIndexedPropertyDescriptor to SimplePropertyDescriptor and preferring direct field access wherever possible. Issue: SPR-10862 (cherry picked from commit 5639aa7) --- .../beans/ExtendedBeanInfo.java | 166 +++++++----------- .../beans/SimplePropertyDescriptorTests.java | 17 +- 2 files changed, 73 insertions(+), 110 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java index 8ad4876c1b..4258aa896e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java +++ b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java @@ -17,7 +17,6 @@ package org.springframework.beans; import java.awt.Image; - import java.beans.BeanDescriptor; import java.beans.BeanInfo; import java.beans.EventSetDescriptor; @@ -26,10 +25,8 @@ import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.MethodDescriptor; import java.beans.PropertyDescriptor; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; - import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -84,8 +81,8 @@ class ExtendedBeanInfo implements BeanInfo { /** * Wrap the given {@link BeanInfo} instance; copy all its existing property descriptors - * locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed} or - * {@link SimpleNonIndexedPropertyDescriptor non-indexed} {@code PropertyDescriptor} + * locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed} + * or {@link SimplePropertyDescriptor non-indexed} {@code PropertyDescriptor} * variant that bypasses default JDK weak/soft reference management; then search * through its method descriptors to find any non-void returning write methods and * update or create the corresponding {@link PropertyDescriptor} for each one found. @@ -96,15 +93,16 @@ class ExtendedBeanInfo implements BeanInfo { */ public ExtendedBeanInfo(BeanInfo delegate) throws IntrospectionException { this.delegate = delegate; - for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) { this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ? new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) : - new SimpleNonIndexedPropertyDescriptor(pd)); + new SimplePropertyDescriptor(pd)); } - - for (Method method : findCandidateWriteMethods(delegate.getMethodDescriptors())) { - handleCandidateWriteMethod(method); + MethodDescriptor[] methodDescriptors = delegate.getMethodDescriptors(); + if (methodDescriptors != null) { + for (Method method : findCandidateWriteMethods(methodDescriptors)) { + handleCandidateWriteMethod(method); + } } } @@ -133,58 +131,44 @@ class ExtendedBeanInfo implements BeanInfo { String methodName = method.getName(); Class[] parameterTypes = method.getParameterTypes(); int nParams = parameterTypes.length; - if (methodName.length() > 3 && methodName.startsWith("set") && - Modifier.isPublic(method.getModifiers()) && - ( - !void.class.isAssignableFrom(method.getReturnType()) || - Modifier.isStatic(method.getModifiers()) - ) && - (nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)))) { - return true; - } - return false; + return methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) && + (!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) && + (nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class))); } private void handleCandidateWriteMethod(Method method) throws IntrospectionException { int nParams = method.getParameterTypes().length; String propertyName = propertyNameFor(method); Class propertyType = method.getParameterTypes()[nParams-1]; - PropertyDescriptor existingPD = findExistingPropertyDescriptor(propertyName, propertyType); + PropertyDescriptor existingPd = findExistingPropertyDescriptor(propertyName, propertyType); if (nParams == 1) { - if (existingPD == null) { - this.propertyDescriptors.add( - new SimpleNonIndexedPropertyDescriptor(propertyName, null, method)); + if (existingPd == null) { + this.propertyDescriptors.add(new SimplePropertyDescriptor(propertyName, null, method)); } else { - existingPD.setWriteMethod(method); + existingPd.setWriteMethod(method); } } else if (nParams == 2) { - if (existingPD == null) { + if (existingPd == null) { this.propertyDescriptors.add( - new SimpleIndexedPropertyDescriptor( - propertyName, null, null, null, method)); + new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method)); } - else if (existingPD instanceof IndexedPropertyDescriptor) { - ((IndexedPropertyDescriptor)existingPD).setIndexedWriteMethod(method); + else if (existingPd instanceof IndexedPropertyDescriptor) { + ((IndexedPropertyDescriptor) existingPd).setIndexedWriteMethod(method); } else { - this.propertyDescriptors.remove(existingPD); - this.propertyDescriptors.add( - new SimpleIndexedPropertyDescriptor( - propertyName, existingPD.getReadMethod(), - existingPD.getWriteMethod(), null, method)); + this.propertyDescriptors.remove(existingPd); + this.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor( + propertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method)); } } else { - throw new IllegalArgumentException( - "write method must have exactly 1 or 2 parameters: " + method); + throw new IllegalArgumentException("Write method must have exactly 1 or 2 parameters: " + method); } } - private PropertyDescriptor findExistingPropertyDescriptor( - String propertyName, Class propertyType) { - + private PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class propertyType) { for (PropertyDescriptor pd : this.propertyDescriptors) { final Class candidateType; final String candidateName = pd.getName(); @@ -192,16 +176,14 @@ class ExtendedBeanInfo implements BeanInfo { IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd; candidateType = ipd.getIndexedPropertyType(); if (candidateName.equals(propertyName) && - (candidateType.equals(propertyType) || - candidateType.equals(propertyType.getComponentType()))) { + (candidateType.equals(propertyType) || candidateType.equals(propertyType.getComponentType()))) { return pd; } } else { candidateType = pd.getPropertyType(); if (candidateName.equals(propertyName) && - (candidateType.equals(propertyType) || - propertyType.equals(candidateType.getComponentType()))) { + (candidateType.equals(propertyType) || propertyType.equals(candidateType.getComponentType()))) { return pd; } } @@ -210,8 +192,7 @@ class ExtendedBeanInfo implements BeanInfo { } private String propertyNameFor(Method method) { - return Introspector.decapitalize( - method.getName().substring(3, method.getName().length())); + return Introspector.decapitalize(method.getName().substring(3, method.getName().length())); } @@ -223,8 +204,7 @@ class ExtendedBeanInfo implements BeanInfo { */ @Override public PropertyDescriptor[] getPropertyDescriptors() { - return this.propertyDescriptors.toArray( - new PropertyDescriptor[this.propertyDescriptors.size()]); + return this.propertyDescriptors.toArray(new PropertyDescriptor[this.propertyDescriptors.size()]); } @Override @@ -264,31 +244,28 @@ class ExtendedBeanInfo implements BeanInfo { } -class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor { +class SimplePropertyDescriptor extends PropertyDescriptor { private Method readMethod; + private Method writeMethod; - private Class propertyType; - private Class propertyEditorClass; + private Class propertyType; - public SimpleNonIndexedPropertyDescriptor(PropertyDescriptor original) - throws IntrospectionException { + private Class propertyEditorClass; + public SimplePropertyDescriptor(PropertyDescriptor original) throws IntrospectionException { this(original.getName(), original.getReadMethod(), original.getWriteMethod()); copyNonMethodProperties(original, this); } - public SimpleNonIndexedPropertyDescriptor(String propertyName, - Method readMethod, Method writeMethod) throws IntrospectionException { - + public SimplePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod) throws IntrospectionException { super(propertyName, null, null); - this.setReadMethod(readMethod); - this.setWriteMethod(writeMethod); + this.readMethod = readMethod; + this.writeMethod = writeMethod; this.propertyType = findPropertyType(readMethod, writeMethod); } - @Override public Method getReadMethod() { return this.readMethod; @@ -314,7 +291,8 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor { if (this.propertyType == null) { try { this.propertyType = findPropertyType(this.readMethod, this.writeMethod); - } catch (IntrospectionException ex) { + } + catch (IntrospectionException ex) { // ignore, as does PropertyDescriptor#getPropertyType } } @@ -331,7 +309,6 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor { this.propertyEditorClass = propertyEditorClass; } - @Override public boolean equals(Object obj) { return PropertyDescriptorUtils.equals(this, obj); @@ -340,8 +317,7 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor { @Override public String toString() { return String.format("%s[name=%s, propertyType=%s, readMethod=%s, writeMethod=%s]", - this.getClass().getSimpleName(), this.getName(), this.getPropertyType(), - this.readMethod, this.writeMethod); + getClass().getSimpleName(), getName(), getPropertyType(), this.readMethod, this.writeMethod); } } @@ -349,40 +325,37 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor { class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor { private Method readMethod; + private Method writeMethod; + private Class propertyType; - private Class propertyEditorClass; private Method indexedReadMethod; + private Method indexedWriteMethod; - private Class indexedPropertyType; + private Class indexedPropertyType; - public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original) - throws IntrospectionException { + private Class propertyEditorClass; + public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original) throws IntrospectionException { this(original.getName(), original.getReadMethod(), original.getWriteMethod(), original.getIndexedReadMethod(), original.getIndexedWriteMethod()); copyNonMethodProperties(original, this); } - public SimpleIndexedPropertyDescriptor(String propertyName, - Method readMethod, Method writeMethod, - Method indexedReadMethod, Method indexedWriteMethod) - throws IntrospectionException { + public SimpleIndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod, + Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException { super(propertyName, null, null, null, null); - this.setReadMethod(readMethod); - this.setWriteMethod(writeMethod); + this.readMethod = readMethod; + this.writeMethod = writeMethod; this.propertyType = findPropertyType(readMethod, writeMethod); - - this.setIndexedReadMethod(indexedReadMethod); - this.setIndexedWriteMethod(indexedWriteMethod); - this.indexedPropertyType = findIndexedPropertyType( - this.getName(), this.propertyType, indexedReadMethod, indexedWriteMethod); + this.indexedReadMethod = indexedReadMethod; + this.indexedWriteMethod = indexedWriteMethod; + this.indexedPropertyType = findIndexedPropertyType(propertyName, this.propertyType, indexedReadMethod, indexedWriteMethod); } - @Override public Method getReadMethod() { return this.readMethod; @@ -408,7 +381,8 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor { if (this.propertyType == null) { try { this.propertyType = findPropertyType(this.readMethod, this.writeMethod); - } catch (IntrospectionException ex) { + } + catch (IntrospectionException ex) { // ignore, as does IndexedPropertyDescriptor#getPropertyType } } @@ -440,9 +414,9 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor { if (this.indexedPropertyType == null) { try { this.indexedPropertyType = findIndexedPropertyType( - this.getName(), this.getPropertyType(), - this.indexedReadMethod, this.indexedWriteMethod); - } catch (IntrospectionException ex) { + getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod); + } + catch (IntrospectionException ex) { // ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType } } @@ -459,26 +433,22 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor { this.propertyEditorClass = propertyEditorClass; } - /* - * @see java.beans.IndexedPropertyDescriptor#equals(java.lang.Object) + * See java.beans.IndexedPropertyDescriptor#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj != null && obj instanceof IndexedPropertyDescriptor) { IndexedPropertyDescriptor other = (IndexedPropertyDescriptor) obj; if (!compareMethods(getIndexedReadMethod(), other.getIndexedReadMethod())) { return false; } - if (!compareMethods(getIndexedWriteMethod(), other.getIndexedWriteMethod())) { return false; } - if (getIndexedPropertyType() != other.getIndexedPropertyType()) { return false; } @@ -491,9 +461,8 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor { public String toString() { return String.format("%s[name=%s, propertyType=%s, indexedPropertyType=%s, " + "readMethod=%s, writeMethod=%s, indexedReadMethod=%s, indexedWriteMethod=%s]", - this.getClass().getSimpleName(), this.getName(), this.getPropertyType(), - this.getIndexedPropertyType(), this.readMethod, this.writeMethod, - this.indexedReadMethod, this.indexedWriteMethod); + getClass().getSimpleName(), getName(), getPropertyType(), getIndexedPropertyType(), + this.readMethod, this.writeMethod, this.indexedReadMethod, this.indexedWriteMethod); } } @@ -501,7 +470,7 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor { class PropertyDescriptorUtils { /* - * see java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor) + * See java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor) */ public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDescriptor target) throws IntrospectionException { @@ -529,11 +498,8 @@ class PropertyDescriptorUtils { /* * See PropertyDescriptor#findPropertyType */ - public static Class findPropertyType(Method readMethod, Method writeMethod) - throws IntrospectionException { - + public static Class findPropertyType(Method readMethod, Method writeMethod) throws IntrospectionException { Class propertyType = null; - if (readMethod != null) { Class[] params = readMethod.getParameterTypes(); if (params.length != 0) { @@ -563,8 +529,7 @@ class PropertyDescriptorUtils { * See IndexedPropertyDescriptor#findIndexedPropertyType */ public static Class findIndexedPropertyType(String name, Class propertyType, - Method indexedReadMethod, Method indexedWriteMethod) - throws IntrospectionException { + Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException { Class indexedPropertyType = null; @@ -614,7 +579,6 @@ class PropertyDescriptorUtils { * return {@code true} if they are objects are equivalent, i.e. both are {@code * PropertyDescriptor}s whose read method, write method, property types, property * editor and flags are equivalent. - * * @see PropertyDescriptor#equals(Object) */ public static boolean equals(PropertyDescriptor pd1, Object obj) { @@ -642,13 +606,12 @@ class PropertyDescriptorUtils { } /* - * see PropertyDescriptor#compareMethods + * See PropertyDescriptor#compareMethods */ public static boolean compareMethods(Method a, Method b) { if ((a == null) != (b == null)) { return false; } - if (a != null && b != null) { if (!a.equals(b)) { return false; @@ -662,7 +625,6 @@ class PropertyDescriptorUtils { /** * Sorts PropertyDescriptor instances alpha-numerically to emulate the behavior of * {@link java.beans.BeanInfo#getPropertyDescriptors()}. - * * @see ExtendedBeanInfo#propertyDescriptors */ class PropertyDescriptorComparator implements Comparator { diff --git a/spring-beans/src/test/java/org/springframework/beans/SimplePropertyDescriptorTests.java b/spring-beans/src/test/java/org/springframework/beans/SimplePropertyDescriptorTests.java index 8627083279..b5a9f14e4f 100644 --- a/spring-beans/src/test/java/org/springframework/beans/SimplePropertyDescriptorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/SimplePropertyDescriptorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; /** - * Unit tests for {@link SimpleNonIndexedPropertyDescriptor} and + * Unit tests for {@link SimplePropertyDescriptor} and * {@link SimpleIndexedPropertyDescriptor}. * * @author Chris Beams @@ -39,7 +39,7 @@ public class SimplePropertyDescriptorTests { @Test public void toStringOutput() throws IntrospectionException, SecurityException, NoSuchMethodException { { - Object pd = new SimpleNonIndexedPropertyDescriptor("foo", null, null); + Object pd = new SimplePropertyDescriptor("foo", null, null); assertThat(pd.toString(), containsString( "PropertyDescriptor[name=foo, propertyType=null, readMethod=null")); } @@ -49,7 +49,7 @@ public class SimplePropertyDescriptorTests { public Object setFoo(String foo) { return null; } } Method m = C.class.getMethod("setFoo", String.class); - Object pd = new SimpleNonIndexedPropertyDescriptor("foo", null, m); + Object pd = new SimplePropertyDescriptor("foo", null, m); assertThat(pd.toString(), allOf( containsString("PropertyDescriptor[name=foo"), containsString("propertyType=class java.lang.String"), @@ -76,10 +76,10 @@ public class SimplePropertyDescriptorTests { @Test public void nonIndexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException { - Object pd1 = new SimpleNonIndexedPropertyDescriptor("foo", null, null); + Object pd1 = new SimplePropertyDescriptor("foo", null, null); assertThat(pd1, equalTo(pd1)); - Object pd2 = new SimpleNonIndexedPropertyDescriptor("foo", null, null); + Object pd2 = new SimplePropertyDescriptor("foo", null, null); assertThat(pd1, equalTo(pd2)); assertThat(pd2, equalTo(pd1)); @@ -89,12 +89,12 @@ public class SimplePropertyDescriptorTests { public String getFoo() { return null; } } Method wm1 = C.class.getMethod("setFoo", String.class); - Object pd3 = new SimpleNonIndexedPropertyDescriptor("foo", null, wm1); + Object pd3 = new SimplePropertyDescriptor("foo", null, wm1); assertThat(pd1, not(equalTo(pd3))); assertThat(pd3, not(equalTo(pd1))); Method rm1 = C.class.getMethod("getFoo"); - Object pd4 = new SimpleNonIndexedPropertyDescriptor("foo", rm1, null); + Object pd4 = new SimplePropertyDescriptor("foo", rm1, null); assertThat(pd1, not(equalTo(pd4))); assertThat(pd4, not(equalTo(pd1))); @@ -147,4 +147,5 @@ public class SimplePropertyDescriptorTests { assertThat(pd1, not(equalTo(pd7))); assertThat(pd7, not(equalTo(pd1))); } + }