Frames | No Frames |
1: /* IndexedPropertyDescriptor.java -- 2: Copyright (C) 1998, 2003 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.beans; 40: 41: import java.lang.reflect.Array; 42: import java.lang.reflect.Method; 43: 44: /** 45: * IndexedPropertyDescriptor describes information about a JavaBean 46: * indexed property, by which we mean an array-like property that 47: * has been exposed via a pair of get and set methods and another 48: * pair that allows you to get to the property by an index.<P> 49: * 50: * An example property would have four methods like this:<P> 51: * <CODE>FooBar[] getFoo()</CODE><BR> 52: * <CODE>void setFoo(FooBar[])</CODE><BR> 53: * <CODE>FooBar getFoo(int)</CODE><BR> 54: * <CODE>void setFoo(int,FooBar)</CODE><P> 55: * 56: * The constraints put on get and set methods are:<P> 57: * <OL> 58: * <LI>There must be at least a get(int) or a set(int,...) method. 59: * Nothing else is required. <B>Spec note:</B>One nice restriction 60: * would be that if there is a get() there must be a get(int), same 61: * with set, but that is not in the spec and is fairly harmless.)</LI> 62: * <LI>A get array method must have signature 63: * <CODE><propertyType>[] <getMethodName>()</CODE></LI> 64: * <LI>A set array method must have signature 65: * <CODE>void <setMethodName>(<propertyType>[])</CODE></LI> 66: * <LI>A get index method must have signature 67: * <CODE><propertyType> <getMethodName>(int)</CODE></LI> 68: * <LI>A set index method must have signature 69: * <CODE>void <setMethodName>(int,<propertyType>)</CODE></LI> 70: * <LI>All these methods may throw any exception.</LI> 71: * <LI>All these methods must be public.</LI> 72: * </OL> 73: * 74: * @author John Keiser 75: * @since JDK1.1 76: */ 77: public class IndexedPropertyDescriptor extends PropertyDescriptor 78: { 79: private Class<?> indexedPropertyType; 80: private Method setIndex; 81: private Method getIndex; 82: 83: /** 84: * Create a new IndexedPropertyDescriptor by introspection. 85: * This form of constructor creates the PropertyDescriptor by 86: * looking for getter methods named <CODE>get<name>()</CODE> 87: * and setter methods named 88: * <CODE>set<name>()</CODE> in class 89: * <CODE><beanClass></CODE>, where <name> has its 90: * first letter capitalized by the constructor.<P> 91: * 92: * <B>Implementation note:</B> If there is a get(int) method, 93: * then the return type of that method is used to find the 94: * remaining methods. If there is no get method, then the 95: * set(int) method is searched for exhaustively and that type 96: * is used to find the others.<P> 97: * 98: * <B>Spec note:</B> 99: * If there is no get(int) method and multiple set(int) methods with 100: * the same name and the correct parameters (different type of course), 101: * then an IntrospectionException is thrown. While Sun's spec 102: * does not state this, it can make Bean behavior different on 103: * different systems (since method order is not guaranteed) and as 104: * such, can be treated as a bug in the spec. I am not aware of 105: * whether Sun's implementation catches this. 106: * 107: * @param name the programmatic name of the property, usually 108: * starting with a lowercase letter (e.g. fooManChu 109: * instead of FooManChu). 110: * @param beanClass the class the get and set methods live in. 111: * 112: * @exception IntrospectionException if the methods are not found or 113: * invalid. 114: */ 115: public IndexedPropertyDescriptor(String name, Class<?> beanClass) 116: throws IntrospectionException 117: { 118: super(name); 119: String capitalized; 120: try 121: { 122: capitalized = Character.toUpperCase(name.charAt(0)) 123: + name.substring(1); 124: } 125: catch(StringIndexOutOfBoundsException e) 126: { 127: capitalized = ""; 128: } 129: findMethods(beanClass, "get" + capitalized, "set" + capitalized, 130: "get" + capitalized, "set" + capitalized); 131: } 132: 133: /** 134: * Create a new IndexedPropertyDescriptor by introspection. 135: * This form of constructor allows you to specify the 136: * names of the get and set methods to search for.<P> 137: * 138: * <B>Implementation note:</B> If there is a get(int) method, 139: * then the return type of that method is used to find the 140: * remaining methods. If there is no get method, then the 141: * set(int) method is searched for exhaustively and that type 142: * is used to find the others.<P> 143: * 144: * <B>Spec note:</B> 145: * If there is no get(int) method and multiple set(int) methods with 146: * the same name and the correct parameters (different type of course), 147: * then an IntrospectionException is thrown. While Sun's spec 148: * does not state this, it can make Bean behavior different on 149: * different systems (since method order is not guaranteed) and as 150: * such, can be treated as a bug in the spec. I am not aware of 151: * whether Sun's implementation catches this. 152: * 153: * @param name the programmatic name of the property, usually 154: * starting with a lowercase letter (e.g. fooManChu 155: * instead of FooManChu). 156: * @param beanClass the class the get and set methods live in. 157: * @param getMethodName the name of the get array method. 158: * @param setMethodName the name of the set array method. 159: * @param getIndexName the name of the get index method. 160: * @param setIndexName the name of the set index method. 161: * 162: * @exception IntrospectionException if the methods are not found or invalid. 163: */ 164: public IndexedPropertyDescriptor(String name, Class<?> beanClass, 165: String getMethodName, String setMethodName, 166: String getIndexName, String setIndexName) 167: throws IntrospectionException 168: { 169: super(name); 170: findMethods(beanClass, getMethodName, setMethodName, getIndexName, 171: setIndexName); 172: } 173: 174: /** 175: * Create a new PropertyDescriptor using explicit Methods. 176: * Note that the methods will be checked for conformance to standard 177: * Property method rules, as described above at the top of this class. 178: * 179: * @param name the programmatic name of the property, usually 180: * starting with a lowercase letter (e.g. fooManChu 181: * instead of FooManChu). 182: * @param getMethod the get array method. 183: * @param setMethod the set array method. 184: * @param getIndex the get index method. 185: * @param setIndex the set index method. 186: * 187: * @exception IntrospectionException if the methods are not found or invalid. 188: */ 189: public IndexedPropertyDescriptor(String name, Method getMethod, 190: Method setMethod, Method getIndex, 191: Method setIndex) 192: throws IntrospectionException 193: { 194: super(name); 195: if(getMethod != null && getMethod.getParameterTypes().length > 0) 196: throw new IntrospectionException("get method has parameters"); 197: if(getMethod != null && setMethod.getParameterTypes().length != 1) 198: throw new IntrospectionException("set method does not have exactly one parameter"); 199: if(getMethod != null && setMethod != null) 200: { 201: if(!getMethod.getReturnType().equals(setMethod.getParameterTypes()[0])) 202: { 203: throw new IntrospectionException("set and get methods do not " 204: + "share the same type"); 205: } 206: if(!getMethod.getDeclaringClass().isAssignableFrom 207: (setMethod.getDeclaringClass()) 208: && !setMethod.getDeclaringClass().isAssignableFrom 209: (getMethod.getDeclaringClass())) 210: { 211: throw new IntrospectionException("set and get methods are not in " 212: + "the same class."); 213: } 214: } 215: 216: if (getIndex != null 217: && (getIndex.getParameterTypes().length != 1 218: || !(getIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE))) 219: { 220: throw new IntrospectionException("get index method has wrong " 221: + "parameters"); 222: } 223: if (setIndex != null 224: && (setIndex.getParameterTypes().length != 2 225: || !(setIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE))) 226: { 227: throw new IntrospectionException("set index method has wrong " 228: + "parameters"); 229: } 230: if (getIndex != null && setIndex != null) 231: { 232: if(!getIndex.getReturnType().equals(setIndex.getParameterTypes()[1])) 233: { 234: throw new IntrospectionException("set index methods do not share " 235: + "the same type"); 236: } 237: if(!getIndex.getDeclaringClass().isAssignableFrom 238: (setIndex.getDeclaringClass()) 239: && !setIndex.getDeclaringClass().isAssignableFrom 240: (getIndex.getDeclaringClass())) 241: { 242: throw new IntrospectionException("get and set index methods are " 243: + "not in the same class."); 244: } 245: } 246: 247: if (getIndex != null && getMethod != null 248: && !getIndex.getDeclaringClass().isAssignableFrom 249: (getMethod.getDeclaringClass()) 250: && !getMethod.getDeclaringClass().isAssignableFrom 251: (getIndex.getDeclaringClass())) 252: { 253: throw new IntrospectionException("methods are not in the same class."); 254: } 255: 256: if (getIndex != null && getMethod != null 257: && !Array.newInstance(getIndex.getReturnType(),0) 258: .getClass().equals(getMethod.getReturnType())) 259: { 260: throw new IntrospectionException("array methods do not match index " 261: + "methods."); 262: } 263: 264: this.getMethod = getMethod; 265: this.setMethod = setMethod; 266: this.getIndex = getIndex; 267: this.setIndex = setIndex; 268: this.indexedPropertyType = getIndex != null ? getIndex.getReturnType() 269: : setIndex.getParameterTypes()[1]; 270: this.propertyType = getMethod != null ? getMethod.getReturnType() 271: : (setMethod != null ? setMethod.getParameterTypes()[0] 272: : Array.newInstance(this.indexedPropertyType,0).getClass()); 273: } 274: 275: public Class<?> getIndexedPropertyType() 276: { 277: return indexedPropertyType; 278: } 279: 280: public Method getIndexedReadMethod() 281: { 282: return getIndex; 283: } 284: 285: /** 286: * Sets the method that is used to read an indexed property. 287: * 288: * @param m the method to set 289: */ 290: public void setIndexedReadMethod(Method m) throws IntrospectionException 291: { 292: getIndex = m; 293: } 294: 295: public Method getIndexedWriteMethod() 296: { 297: return setIndex; 298: } 299: 300: /** 301: * Sets the method that is used to write an indexed property. 302: * 303: * @param m the method to set 304: */ 305: public void setIndexedWriteMethod(Method m) throws IntrospectionException 306: { 307: setIndex = m; 308: } 309: 310: private void findMethods(Class beanClass, String getMethodName, 311: String setMethodName, String getIndexName, 312: String setIndexName) 313: throws IntrospectionException 314: { 315: try 316: { 317: if(getIndexName != null) 318: { 319: try 320: { 321: Class[] getArgs = new Class[1]; 322: getArgs[0] = java.lang.Integer.TYPE; 323: getIndex = beanClass.getMethod(getIndexName,getArgs); 324: indexedPropertyType = getIndex.getReturnType(); 325: } 326: catch(NoSuchMethodException E) 327: { 328: } 329: } 330: if(getIndex != null) 331: { 332: if(setIndexName != null) 333: { 334: try 335: { 336: Class[] setArgs = new Class[2]; 337: setArgs[0] = java.lang.Integer.TYPE; 338: setArgs[1] = indexedPropertyType; 339: setIndex = beanClass.getMethod(setIndexName,setArgs); 340: if(!setIndex.getReturnType().equals(java.lang.Void.TYPE)) 341: { 342: throw new IntrospectionException(setIndexName 343: + " has non-void return type"); 344: } 345: } 346: catch(NoSuchMethodException E) 347: { 348: } 349: } 350: } 351: else if(setIndexName != null) 352: { 353: Method[] m = beanClass.getMethods(); 354: for(int i=0;i<m.length;i++) 355: { 356: Method current = m[i]; 357: if(current.getName().equals(setIndexName) 358: && current.getParameterTypes().length == 2 359: && (current.getParameterTypes()[0]) 360: .equals(java.lang.Integer.TYPE) 361: && current.getReturnType().equals(java.lang.Void.TYPE)) 362: { 363: if(setIndex != null) 364: { 365: throw new IntrospectionException("Multiple, different " 366: + "set methods found that fit the bill!"); 367: } 368: else 369: { 370: setIndex = current; 371: indexedPropertyType = current.getParameterTypes()[1]; 372: } 373: } 374: } 375: if(setIndex == null) 376: { 377: throw new IntrospectionException("Cannot find get or set " 378: + "methods."); 379: } 380: } 381: else 382: { 383: throw new IntrospectionException("Cannot find get or set methods."); 384: } 385: 386: Class arrayType = Array.newInstance(indexedPropertyType,0).getClass(); 387: 388: Class[] setArgs = new Class[1]; 389: setArgs[0] = arrayType; 390: try 391: { 392: setMethod = beanClass.getMethod(setMethodName,setArgs); 393: if (!setMethod.getReturnType().equals(java.lang.Void.TYPE)) 394: { 395: setMethod = null; 396: } 397: } 398: catch(NoSuchMethodException E) 399: { 400: } 401: 402: Class[] getArgs = new Class[0]; 403: try 404: { 405: getMethod = beanClass.getMethod(getMethodName,getArgs); 406: if (!getMethod.getReturnType().equals(arrayType)) 407: { 408: getMethod = null; 409: } 410: } 411: catch(NoSuchMethodException E) 412: { 413: } 414: } 415: catch(SecurityException E) 416: { 417: throw new IntrospectionException("SecurityException while trying to " 418: + "find methods."); 419: } 420: } 421: }