GNU Classpath (0.18) | ||
Frames | No Frames |
1: /* java.beans.IndexedPropertyDescriptor 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: ** @version 1.1.0, 26 Jul 1998 77: **/ 78: 79: public class IndexedPropertyDescriptor extends PropertyDescriptor { 80: private Class indexedPropertyType; 81: private Method setIndex; 82: private Method getIndex; 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: ** @exception IntrospectionException if the methods are not found or invalid. 112: **/ 113: public IndexedPropertyDescriptor(String name, Class beanClass) throws IntrospectionException { 114: super(name); 115: String capitalized; 116: try { 117: capitalized = Character.toUpperCase(name.charAt(0)) + name.substring(1); 118: } catch(StringIndexOutOfBoundsException e) { 119: capitalized = ""; 120: } 121: findMethods(beanClass, "get" + capitalized, "set" + capitalized, "get" + capitalized, "set" + capitalized); 122: } 123: 124: /** Create a new IndexedPropertyDescriptor by introspection. 125: ** This form of constructor allows you to specify the 126: ** names of the get and set methods to search for.<P> 127: ** 128: ** <B>Implementation note:</B> If there is a get(int) method, 129: ** then the return type of that method is used to find the 130: ** remaining methods. If there is no get method, then the 131: ** set(int) method is searched for exhaustively and that type 132: ** is used to find the others.<P> 133: ** 134: ** <B>Spec note:</B> 135: ** If there is no get(int) method and multiple set(int) methods with 136: ** the same name and the correct parameters (different type of course), 137: ** then an IntrospectionException is thrown. While Sun's spec 138: ** does not state this, it can make Bean behavior different on 139: ** different systems (since method order is not guaranteed) and as 140: ** such, can be treated as a bug in the spec. I am not aware of 141: ** whether Sun's implementation catches this. 142: ** 143: ** @param name the programmatic name of the property, usually 144: ** starting with a lowercase letter (e.g. fooManChu 145: ** instead of FooManChu). 146: ** @param beanClass the class the get and set methods live in. 147: ** @param getMethodName the name of the get array method. 148: ** @param setMethodName the name of the set array method. 149: ** @param getIndexName the name of the get index method. 150: ** @param setIndexName the name of the set index method. 151: ** @exception IntrospectionException if the methods are not found or invalid. 152: **/ 153: public IndexedPropertyDescriptor(String name, Class beanClass, String getMethodName, String setMethodName, String getIndexName, String setIndexName) throws IntrospectionException { 154: super(name); 155: findMethods(beanClass, getMethodName, setMethodName, getIndexName, setIndexName); 156: } 157: 158: /** Create a new PropertyDescriptor using explicit Methods. 159: ** Note that the methods will be checked for conformance to standard 160: ** Property method rules, as described above at the top of this class. 161: ** 162: ** @param name the programmatic name of the property, usually 163: ** starting with a lowercase letter (e.g. fooManChu 164: ** instead of FooManChu). 165: ** @param getMethod the get array method. 166: ** @param setMethod the set array method. 167: ** @param getIndex the get index method. 168: ** @param setIndex the set index method. 169: ** @exception IntrospectionException if the methods are not found or invalid. 170: **/ 171: public IndexedPropertyDescriptor(String name, Method getMethod, Method setMethod, Method getIndex, Method setIndex) throws IntrospectionException { 172: super(name); 173: if(getMethod != null && getMethod.getParameterTypes().length > 0) { 174: throw new IntrospectionException("get method has parameters"); 175: } 176: if(getMethod != null && setMethod.getParameterTypes().length != 1) { 177: throw new IntrospectionException("set method does not have exactly one parameter"); 178: } 179: if(getMethod != null && setMethod != null) { 180: if(!getMethod.getReturnType().equals(setMethod.getParameterTypes()[0])) { 181: throw new IntrospectionException("set and get methods do not share the same type"); 182: } 183: if(!getMethod.getDeclaringClass().isAssignableFrom(setMethod.getDeclaringClass()) 184: && !setMethod.getDeclaringClass().isAssignableFrom(getMethod.getDeclaringClass())) { 185: throw new IntrospectionException("set and get methods are not in the same class."); 186: } 187: } 188: 189: if(getIndex != null && (getIndex.getParameterTypes().length != 1 190: || !(getIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE))) { 191: throw new IntrospectionException("get index method has wrong parameters"); 192: } 193: if(setIndex != null && (setIndex.getParameterTypes().length != 2 194: || !(setIndex.getParameterTypes()[0]).equals(java.lang.Integer.TYPE))) { 195: throw new IntrospectionException("set index method has wrong parameters"); 196: } 197: if(getIndex != null && setIndex != null) { 198: if(!getIndex.getReturnType().equals(setIndex.getParameterTypes()[1])) { 199: throw new IntrospectionException("set index methods do not share the same type"); 200: } 201: if(!getIndex.getDeclaringClass().isAssignableFrom(setIndex.getDeclaringClass()) 202: && !setIndex.getDeclaringClass().isAssignableFrom(getIndex.getDeclaringClass())) { 203: throw new IntrospectionException("get and set index methods are not in the same class."); 204: } 205: } 206: 207: if(getIndex != null && getMethod != null && !getIndex.getDeclaringClass().isAssignableFrom(getMethod.getDeclaringClass()) 208: && !getMethod.getDeclaringClass().isAssignableFrom(getIndex.getDeclaringClass())) { 209: throw new IntrospectionException("methods are not in the same class."); 210: } 211: 212: if(getIndex != null && getMethod != null && !Array.newInstance(getIndex.getReturnType(),0).getClass().equals(getMethod.getReturnType())) { 213: throw new IntrospectionException("array methods do not match index methods."); 214: } 215: 216: this.getMethod = getMethod; 217: this.setMethod = setMethod; 218: this.getIndex = getIndex; 219: this.setIndex = setIndex; 220: this.indexedPropertyType = getIndex != null ? getIndex.getReturnType() : setIndex.getParameterTypes()[1]; 221: this.propertyType = getMethod != null ? getMethod.getReturnType() : (setMethod != null ? setMethod.getParameterTypes()[0] : Array.newInstance(this.indexedPropertyType,0).getClass()); 222: } 223: 224: public Class getIndexedPropertyType() { 225: return indexedPropertyType; 226: } 227: 228: public Method getIndexedReadMethod() { 229: return getIndex; 230: } 231: 232: public Method getIndexedWriteMethod() { 233: return setIndex; 234: } 235: 236: private void findMethods(Class beanClass, String getMethodName, String setMethodName, String getIndexName, String setIndexName) throws IntrospectionException { 237: try { 238: if(getIndexName != null) { 239: try { 240: Class[] getArgs = new Class[1]; 241: getArgs[0] = java.lang.Integer.TYPE; 242: getIndex = beanClass.getMethod(getIndexName,getArgs); 243: indexedPropertyType = getIndex.getReturnType(); 244: } catch(NoSuchMethodException E) { 245: } 246: } 247: if(getIndex != null) { 248: if(setIndexName != null) { 249: try { 250: Class[] setArgs = new Class[2]; 251: setArgs[0] = java.lang.Integer.TYPE; 252: setArgs[1] = indexedPropertyType; 253: setIndex = beanClass.getMethod(setIndexName,setArgs); 254: if(!setIndex.getReturnType().equals(java.lang.Void.TYPE)) { 255: throw new IntrospectionException(setIndexName + " has non-void return type"); 256: } 257: } catch(NoSuchMethodException E) { 258: } 259: } 260: } else if(setIndexName != null) { 261: Method[] m = beanClass.getMethods(); 262: for(int i=0;i<m.length;i++) { 263: Method current = m[i]; 264: if(current.getName().equals(setIndexName) 265: && current.getParameterTypes().length == 2 266: && (current.getParameterTypes()[0]).equals(java.lang.Integer.TYPE) 267: && current.getReturnType().equals(java.lang.Void.TYPE)) { 268: if(setIndex != null) { 269: throw new IntrospectionException("Multiple, different set methods found that fit the bill!"); 270: } else { 271: setIndex = current; 272: indexedPropertyType = current.getParameterTypes()[1]; 273: } 274: } 275: } 276: if(setIndex == null) { 277: throw new IntrospectionException("Cannot find get or set methods."); 278: } 279: } else { 280: throw new IntrospectionException("Cannot find get or set methods."); 281: } 282: 283: Class arrayType = Array.newInstance(indexedPropertyType,0).getClass(); 284: 285: Class[] setArgs = new Class[1]; 286: setArgs[0] = arrayType; 287: try { 288: setMethod = beanClass.getMethod(setMethodName,setArgs); 289: if(!setMethod.getReturnType().equals(java.lang.Void.TYPE)) { 290: setMethod = null; 291: } 292: } catch(NoSuchMethodException E) { 293: } 294: 295: Class[] getArgs = new Class[0]; 296: try { 297: getMethod = beanClass.getMethod(getMethodName,getArgs); 298: if(!getMethod.getReturnType().equals(arrayType)) { 299: getMethod = null; 300: } 301: } catch(NoSuchMethodException E) { 302: } 303: } catch(SecurityException E) { 304: throw new IntrospectionException("SecurityException while trying to find methods."); 305: } 306: } 307: }
GNU Classpath (0.18) |