craigmcc 01/02/02 18:12:25 Modified: src/share/org/apache/struts/util PropertyUtils.java Log: Make property introspection smarter, so that you can invoke a method that is public in an implemented interface, even if the implementing class is not itself public. Among other things, this makes iteration over the Map.Entry values returned for a Map work correctly. Hats off to Martin for figuring out how to do this!!! Submitted by: Martin Cooper <[EMAIL PROTECTED]> Revision Changes Path 1.12 +89 -8 jakarta-struts/src/share/org/apache/struts/util/PropertyUtils.java Index: PropertyUtils.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/PropertyUtils.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- PropertyUtils.java 2001/01/10 01:54:21 1.11 +++ PropertyUtils.java 2001/02/03 02:12:25 1.12 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/PropertyUtils.java,v 1.11 2001/01/10 01:54:21 craigmcc Exp $ - * $Revision: 1.11 $ - * $Date: 2001/01/10 01:54:21 $ + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/PropertyUtils.java,v 1.12 2001/02/03 02:12:25 craigmcc Exp $ + * $Revision: 1.12 $ + * $Date: 2001/02/03 02:12:25 $ * * ==================================================================== * @@ -71,6 +71,7 @@ import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; /** @@ -116,7 +117,7 @@ * @author Craig R. McClanahan * @author Ralph Schaer * @author Chris Audley - * @version $Revision: 1.11 $ $Date: 2001/01/10 01:54:21 $ + * @version $Revision: 1.12 $ $Date: 2001/02/03 02:12:25 $ */ public final class PropertyUtils { @@ -298,7 +299,7 @@ } // Otherwise, the underlying property must be an array - Method readMethod = descriptor.getReadMethod(); + Method readMethod = getReadMethod(descriptor); if (readMethod == null) throw new NoSuchMethodException("Property '" + name + "' has no getter method"); @@ -581,7 +582,7 @@ if (descriptor == null) throw new NoSuchMethodException("Unknown property '" + name + "'"); - Method readMethod = descriptor.getReadMethod(); + Method readMethod = getReadMethod(descriptor); if (readMethod == null) throw new NoSuchMethodException("Property '" + name + "' has no getter method"); @@ -690,7 +691,7 @@ } // Otherwise, the underlying property must be an array - Method readMethod = descriptor.getReadMethod(); + Method readMethod = descriptor.getReadMethod(); if (readMethod == null) throw new NoSuchMethodException("Property '" + name + "' has no getter method"); @@ -813,7 +814,7 @@ if (descriptor == null) throw new NoSuchMethodException("Unknown property '" + name + "'"); - Method writeMethod = descriptor.getWriteMethod(); + Method writeMethod = getWriteMethod(descriptor); if (writeMethod == null) throw new NoSuchMethodException("Property '" + name + "' has no setter method"); @@ -822,6 +823,86 @@ Object values[] = new Object[1]; values[0] = value; writeMethod.invoke(bean, values); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Return an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return <code>null</code>. + * + * @param method The method that we wish to call + */ + private static Method getAccessibleMethod(Method method) { + + // Make sure we have a method to check + if (method == null) { + return (null); + } + + // If the requested method is not public we cannot call it + if (!Modifier.isPublic(method.getModifiers())) { + return (null); + } + + // If the declaring class is public, we are done + Class clazz = method.getDeclaringClass(); + if (Modifier.isPublic(clazz.getModifiers())) { + return (method); + } + + // Check the implemented interfaces + String methodName = method.getName(); + Class[] parameterTypes = method.getParameterTypes(); + Class[] interfaces = clazz.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + method = interfaces[i].getDeclaredMethod(methodName, + parameterTypes); + } catch (NoSuchMethodException e) { + continue; + } + // We have found what we are looking for + return (method); + } + + // We are out of luck + return (null); + + } + + + /** + * Return an accessible property getter method for this property, + * if there is one; otherwise return <code>null</code>. + * + * @param descriptor Property descriptor to return a getter for + */ + private static Method getReadMethod(PropertyDescriptor descriptor) { + + return (getAccessibleMethod(descriptor.getReadMethod())); + + } + + + /** + * Return an accessible property setter method for this property, + * if there is one; otherwise return <code>null</code>. + * + * @param descriptor Property descriptor to return a setter for + */ + private static Method getWriteMethod(PropertyDescriptor descriptor) { + + return (getAccessibleMethod(descriptor.getWriteMethod())); }