diff options
author | Stephen Crawley <crawley@dstc.edu.au> | 2003-02-07 20:19:53 +0000 |
---|---|---|
committer | Mark Wielaard <mark@gcc.gnu.org> | 2003-02-07 20:19:53 +0000 |
commit | b20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e (patch) | |
tree | 5ba867c6dfed9c3a71e924ab93866436f2e9ea98 /libjava/java | |
parent | 7bf0a5935361a7af3bf7823d6733c2f691a7529f (diff) | |
download | gcc-b20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e.zip gcc-b20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e.tar.gz gcc-b20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e.tar.bz2 |
Stephen Crawley <crawley@dstc.edu.au>
* java/beans/PropertyDescriptor.java
(PropertyDescriptor(String, Class)): Sanity check getter and setter
methods.
(PropertyDescriptor(String, Class, String, String)): Likewise.
(PropertyDescriptor(String, Method, Method): Factor out getter and
setter method sanity checks into new method.
(findMethods): Don't do parameter sanity checking of get method here.
(checkMethods): New method.
2003-02-07 Stephen Crawley <crawley@dstc.edu.au>
* java/beans/PropertyDescriptor.java: Reformat.
From-SVN: r62537
Diffstat (limited to 'libjava/java')
-rw-r--r-- | libjava/java/beans/PropertyDescriptor.java | 566 |
1 files changed, 299 insertions, 267 deletions
diff --git a/libjava/java/beans/PropertyDescriptor.java b/libjava/java/beans/PropertyDescriptor.java index b75cac9..00db416 100644 --- a/libjava/java/beans/PropertyDescriptor.java +++ b/libjava/java/beans/PropertyDescriptor.java @@ -65,280 +65,312 @@ import java.lang.reflect.*; **/ public class PropertyDescriptor extends FeatureDescriptor { - Class propertyType; - Method getMethod; - Method setMethod; - - Class propertyEditorClass; - boolean bound; - boolean constrained; - - PropertyDescriptor(String name) { - setName(name); - } - - /** Create a new PropertyDescriptor by introspection. - ** This form of constructor creates the PropertyDescriptor by - ** looking for a getter method named <CODE>get<name>()</CODE> - ** (or, optionally, if the property is boolean, - ** <CODE>is<name>()</CODE>) and - ** <CODE>set<name>()</CODE> in class - ** <CODE><beanClass></CODE>, where <name> has its - ** first letter capitalized by the constructor.<P> - ** - ** <B>Implementation note:</B> If there is a get method (or - ** boolean isXXX() method), then the return type of that method - ** is used to find the set method. If there is no get method, - ** then the set method is searched for exhaustively.<P> - ** - ** <B>Spec note:</B> - ** If there is no get method and multiple set methods with - ** the same name and a single parameter (different type of course), - ** then an IntrospectionException is thrown. While Sun's spec - ** does not state this, it can make Bean behavior different on - ** different systems (since method order is not guaranteed) and as - ** such, can be treated as a bug in the spec. I am not aware of - ** whether Sun's implementation catches this. - ** - ** @param name the programmatic name of the property, usually - ** starting with a lowercase letter (e.g. fooManChu - ** instead of FooManChu). - ** @param beanClass the class the get and set methods live in. - ** @exception IntrospectionException if the methods are not found or invalid. - **/ - public PropertyDescriptor(String name, Class beanClass) throws IntrospectionException { - setName(name); - String capitalized; - try { - capitalized = Character.toUpperCase(name.charAt(0)) + name.substring(1); - } catch(StringIndexOutOfBoundsException e) { - capitalized = ""; - } - findMethods(beanClass, "is" + capitalized, "get" + capitalized, "set" + capitalized); - } - - /** Create a new PropertyDescriptor by introspection. - ** This form of constructor allows you to specify the - ** names of the get and set methods to search for.<P> - ** - ** <B>Implementation note:</B> If there is a get method (or - ** boolean isXXX() method), then the return type of that method - ** is used to find the set method. If there is no get method, - ** then the set method is searched for exhaustively.<P> - ** - ** <B>Spec note:</B> - ** If there is no get method and multiple set methods with - ** the same name and a single parameter (different type of course), - ** then an IntrospectionException is thrown. While Sun's spec - ** does not state this, it can make Bean behavior different on - ** different systems (since method order is not guaranteed) and as - ** such, can be treated as a bug in the spec. I am not aware of - ** whether Sun's implementation catches this. - ** - ** @param name the programmatic name of the property, usually - ** starting with a lowercase letter (e.g. fooManChu - ** instead of FooManChu). - ** @param beanClass the class the get and set methods live in. - ** @param getMethodName the name of the get method. - ** @param setMethodName the name of the set method. - ** @exception IntrospectionException if the methods are not found or invalid. - **/ - public PropertyDescriptor(String name, Class beanClass, String getMethodName, String setMethodName) throws IntrospectionException { - setName(name); - findMethods(beanClass, getMethodName, null, setMethodName); - } - - /** Create a new PropertyDescriptor using explicit Methods. - ** Note that the methods will be checked for conformance to standard - ** Property method rules, as described above at the top of this class. - ** - ** @param name the programmatic name of the property, usually - ** starting with a lowercase letter (e.g. fooManChu - ** instead of FooManChu). - ** @param getMethod the get method. - ** @param setMethod the set method. - ** @exception IntrospectionException if the methods are not found or invalid. - **/ - public PropertyDescriptor(String name, Method getMethod, Method setMethod) throws IntrospectionException { - setName(name); - if(getMethod != null && getMethod.getParameterTypes().length > 0) { - throw new IntrospectionException("get method has parameters"); - } - if(setMethod != null && setMethod.getParameterTypes().length != 1) { - throw new IntrospectionException("set method does not have exactly one parameter"); - } - if(getMethod != null && setMethod != null) { - if(!getMethod.getReturnType().equals(setMethod.getParameterTypes()[0])) { - throw new IntrospectionException("set and get methods do not share the same type"); - } - if(!getMethod.getDeclaringClass().isAssignableFrom(setMethod.getDeclaringClass()) - && !setMethod.getDeclaringClass().isAssignableFrom(getMethod.getDeclaringClass())) { - throw new IntrospectionException("set and get methods are not in the same class."); - } - } - this.getMethod = getMethod; - this.setMethod = setMethod; - if(getMethod != null) { - this.propertyType = getMethod.getReturnType(); - } else { - this.propertyType = setMethod.getParameterTypes()[0]; - } - } - - /** Get the property type. - ** This is the type the get method returns and the set method - ** takes in. - **/ - public Class getPropertyType() { - return propertyType; - } - - /** Get the get method. Why they call it readMethod here and - ** get everywhere else is beyond me. - **/ - public Method getReadMethod() { - return getMethod; - } - - /** Get the set method. Why they call it writeMethod here and - ** set everywhere else is beyond me. - **/ - public Method getWriteMethod() { - return setMethod; + Class propertyType; + Method getMethod; + Method setMethod; + + Class propertyEditorClass; + boolean bound; + boolean constrained; + + PropertyDescriptor(String name) { + setName(name); + } + + /** Create a new PropertyDescriptor by introspection. + ** This form of constructor creates the PropertyDescriptor by + ** looking for a getter method named <CODE>get<name>()</CODE> + ** (or, optionally, if the property is boolean, + ** <CODE>is<name>()</CODE>) and + ** <CODE>set<name>()</CODE> in class + ** <CODE><beanClass></CODE>, where <name> has its + ** first letter capitalized by the constructor.<P> + ** + ** <B>Implementation note:</B> If there is both are both isXXX and + ** getXXX methods, the former is used in preference to the latter. + ** We do not check that an isXXX method returns a boolean. In both + ** cases, this matches the behaviour of JDK 1.4<P> + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param beanClass the class the get and set methods live in. + ** @exception IntrospectionException if the methods are not found + ** or invalid. + **/ + public PropertyDescriptor(String name, Class beanClass) + throws IntrospectionException + { + setName(name); + if (name.length() == 0) { + throw new IntrospectionException("empty property name"); + } + String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1); + findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps); + if (getMethod == null) { + throw new IntrospectionException("Cannot find an is" + caps + + " or get" + caps + " method"); + } + if (setMethod == null) { + throw new IntrospectionException("Cannot find a " + caps + " method"); + } + checkMethods(); + } + + /** Create a new PropertyDescriptor by introspection. + ** This form of constructor allows you to specify the + ** names of the get and set methods to search for.<P> + ** + ** <B>Implementation note:</B> If there is a get method (or + ** boolean isXXX() method), then the return type of that method + ** is used to find the set method. If there is no get method, + ** then the set method is searched for exhaustively.<P> + ** + ** <B>Spec note:</B> + ** If there is no get method and multiple set methods with + ** the same name and a single parameter (different type of course), + ** then an IntrospectionException is thrown. While Sun's spec + ** does not state this, it can make Bean behavior different on + ** different systems (since method order is not guaranteed) and as + ** such, can be treated as a bug in the spec. I am not aware of + ** whether Sun's implementation catches this. + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param beanClass the class the get and set methods live in. + ** @param getMethodName the name of the get method. + ** @param setMethodName the name of the set method. + ** @exception IntrospectionException if the methods are not found + ** or invalid. + **/ + public PropertyDescriptor(String name, Class beanClass, + String getMethodName, String setMethodName) + throws IntrospectionException + { + setName(name); + findMethods(beanClass, getMethodName, null, setMethodName); + if (getMethod == null && getMethodName != null) { + throw new IntrospectionException("Cannot find a getter method called " + + getMethodName); + } + if (setMethod == null && setMethodName != null) { + throw new IntrospectionException("Cannot find a setter method called " + + setMethodName); + } + checkMethods(); + } + + /** Create a new PropertyDescriptor using explicit Methods. + ** Note that the methods will be checked for conformance to standard + ** Property method rules, as described above at the top of this class. + ** + ** @param name the programmatic name of the property, usually + ** starting with a lowercase letter (e.g. fooManChu + ** instead of FooManChu). + ** @param getMethod the get method. + ** @param setMethod the set method. + ** @exception IntrospectionException if the methods are not found + ** or invalid. + **/ + public PropertyDescriptor(String name, Method getMethod, Method setMethod) + throws IntrospectionException + { + setName(name); + this.getMethod = getMethod; + this.setMethod = setMethod; + if (getMethod != null) { + this.propertyType = getMethod.getReturnType(); + } + else if (setMethod != null) { + this.propertyType = setMethod.getParameterTypes()[0]; + } + checkMethods(); + } + + /** Get the property type. + ** This is the type the get method returns and the set method + ** takes in. + **/ + public Class getPropertyType() { + return propertyType; + } + + /** Get the get method. Why they call it readMethod here and + ** get everywhere else is beyond me. + **/ + public Method getReadMethod() { + return getMethod; + } + + /** Get the set method. Why they call it writeMethod here and + ** set everywhere else is beyond me. + **/ + public Method getWriteMethod() { + return setMethod; + } + + /** Get whether the property is bound. Defaults to false. **/ + public boolean isBound() { + return bound; + } + + /** Set whether the property is bound. + ** As long as the the bean implements addPropertyChangeListener() and + ** removePropertyChangeListener(), setBound(true) may safely be called.<P> + ** If these things are not true, then the behavior of the system + ** will be undefined.<P> + ** + ** When a property is bound, its set method is required to fire the + ** <CODE>PropertyChangeListener.propertyChange())</CODE> event + ** after the value has changed. + ** @param bound whether the property is bound or not. + **/ + public void setBound(boolean bound) { + this.bound = bound; + } + + /** Get whether the property is constrained. Defaults to false. **/ + public boolean isConstrained() { + return constrained; + } + + /** Set whether the property is constrained. + ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE> + ** (or subclass thereof) and the bean implements addVetoableChangeListener() + ** and removeVetoableChangeListener(), then setConstrained(true) may safely + ** be called. Otherwise, the system behavior is undefined. + ** <B>Spec note:</B> given those strict parameters, it would be nice if it + ** got set automatically by detection, but oh well.<P> + ** When a property is constrained, its set method is required to:<P> + ** <OL> + ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE> + ** event notifying others of the change and allowing them a chance to + ** say it is a bad thing.</LI> + ** <LI>If any of the listeners throws a PropertyVetoException, then + ** it must fire another vetoableChange() event notifying the others + ** of a reversion to the old value (though, of course, the change + ** was never made). Then it rethrows the PropertyVetoException and + ** exits.</LI> + ** <LI>If all has gone well to this point, the value may be changed.</LI> + ** </OL> + ** @param constrained whether the property is constrained or not. + **/ + public void setConstrained(boolean constrained) { + this.constrained = constrained; + } + + /** Get the PropertyEditor class. Defaults to null. **/ + public Class getPropertyEditorClass() { + return propertyEditorClass; + } + + /** Set the PropertyEditor class. If the class does not implement + ** the PropertyEditor interface, you will likely get an exception + ** late in the game. + ** @param propertyEditorClass the PropertyEditor class for this + ** class to use. + **/ + public void setPropertyEditorClass(Class propertyEditorClass) { + this.propertyEditorClass = propertyEditorClass; + } + + private void findMethods(Class beanClass, String getMethodName1, + String getMethodName2, String setMethodName) + throws IntrospectionException + { + try { + // Try the first get method name + if (getMethodName1 != null) { + try { + getMethod = beanClass.getMethod(getMethodName1, new Class[0]); + } + catch (NoSuchMethodException e) { } + } - /** Get whether the property is bound. Defaults to false. **/ - public boolean isBound() { - return bound; + // Fall back to the second get method name + if (getMethod == null && getMethodName2 != null) { + try { + getMethod = beanClass.getMethod(getMethodName2, new Class[0]); + } + catch (NoSuchMethodException e) { } + } - /** Set whether the property is bound. - ** As long as the the bean implements addPropertyChangeListener() and - ** removePropertyChangeListener(), setBound(true) may safely be called.<P> - ** If these things are not true, then the behavior of the system - ** will be undefined.<P> - ** - ** When a property is bound, its set method is required to fire the - ** <CODE>PropertyChangeListener.propertyChange())</CODE> event - ** after the value has changed. - ** @param bound whether the property is bound or not. - **/ - public void setBound(boolean bound) { - this.bound = bound; + // Try the set method name + if (setMethodName != null) { + if (getMethod != null) { + // If there is a get method, use its return type to help + // select the corresponding set method. + Class propertyType = getMethod.getReturnType(); + if (propertyType == Void.TYPE) { + String msg = "The property's read method has return type 'void'"; + throw new IntrospectionException(msg); + } + + Class[] setArgs = new Class[]{propertyType}; + try { + setMethod = beanClass.getMethod(setMethodName, setArgs); + } + catch (NoSuchMethodException e) { + } } - - /** Get whether the property is constrained. Defaults to false. **/ - public boolean isConstrained() { - return constrained; - } - - /** Set whether the property is constrained. - ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE> - ** (or subclass thereof) and the bean implements addVetoableChangeListener() - ** and removeVetoableChangeListener(), then setConstrained(true) may safely - ** be called. Otherwise, the system behavior is undefined. - ** <B>Spec note:</B> given those strict parameters, it would be nice if it - ** got set automatically by detection, but oh well.<P> - ** When a property is constrained, its set method is required to:<P> - ** <OL> - ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE> - ** event notifying others of the change and allowing them a chance to - ** say it is a bad thing.</LI> - ** <LI>If any of the listeners throws a PropertyVetoException, then - ** it must fire another vetoableChange() event notifying the others - ** of a reversion to the old value (though, of course, the change - ** was never made). Then it rethrows the PropertyVetoException and - ** exits.</LI> - ** <LI>If all has gone well to this point, the value may be changed.</LI> - ** </OL> - ** @param constrained whether the property is constrained or not. - **/ - public void setConstrained(boolean constrained) { - this.constrained = constrained; + else if (getMethodName1 == null && getMethodName2 == null) { + // If this is a write-only property, choose the first set method + // with the required name, one parameter and return type 'void' + Method[] methods = beanClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(setMethodName) && + methods[i].getParameterTypes().length == 1 && + methods[i].getReturnType() == Void.TYPE) { + setMethod = methods[i]; + break; + } + } } + } + } + catch (SecurityException e) { + // FIXME -- shouldn't we just allow SecurityException to propagate? + String msg = "SecurityException thrown on attempt to access methods."; + throw new IntrospectionException(msg); + } + } - /** Get the PropertyEditor class. Defaults to null. **/ - public Class getPropertyEditorClass() { - return propertyEditorClass; + private void checkMethods() + throws IntrospectionException + { + if (getMethod != null) { + if (getMethod.getParameterTypes().length > 0) { + throw new IntrospectionException("get method has parameters"); + } + this.propertyType = getMethod.getReturnType(); + if (propertyType == Void.TYPE) { + throw new IntrospectionException("get method has void return type"); + } + } + if (setMethod != null) { + if (setMethod.getParameterTypes().length != 1) { + String msg = "set method does not have exactly one parameter"; + throw new IntrospectionException(msg); + } + if (getMethod == null) { + propertyType = setMethod.getParameterTypes()[0]; + } + else { + if (!propertyType.equals(setMethod.getParameterTypes()[0])) { + String msg = "set and get methods do not share the same type"; + throw new IntrospectionException(msg); } - - /** Set the PropertyEditor class. If the class does not implement - ** the PropertyEditor interface, you will likely get an exception - ** late in the game. - ** @param propertyEditorClass the PropertyEditor class for this class to use. - **/ - public void setPropertyEditorClass(Class propertyEditorClass) { - this.propertyEditorClass = propertyEditorClass; - } - - private void findMethods(Class beanClass, String getMethodName1, String getMethodName2, String setMethodName) throws IntrospectionException { - try { - if(getMethodName1 != null) { - try { - getMethod = beanClass.getMethod(getMethodName1, new Class[0]); - } catch(NoSuchMethodException E) { - } - if(getMethodName2 != null) { - if(getMethod != null && !getMethod.getReturnType().equals(java.lang.Boolean.TYPE)) { - // If the is() method exists but isn't boolean, we'll just go on and look for - // an ordinary get() method. - getMethod = null; - } - - Method getMethod2; - try { - getMethod2 = beanClass.getMethod(getMethodName2, new Class[0]); - } catch(NoSuchMethodException E) { - getMethod2 = null; - } - if(getMethod2 != null) { - if(getMethod != null) { - if(!getMethod.getReturnType().equals(getMethod2.getReturnType())) { - throw new IntrospectionException("Both " + getMethodName1 + " and " + getMethodName2 + " exist, and have contradictory return types."); - } - } else { - getMethod = getMethod2; - } - } - } - } - - if(getMethod != null) { - propertyType = getMethod.getReturnType(); - if(setMethodName != null) { - Class[] setArgs = new Class[1]; - setArgs[0] = propertyType; - try { - setMethod = beanClass.getMethod(setMethodName, setArgs); - if(!setMethod.getReturnType().equals(java.lang.Void.TYPE)) { - throw new IntrospectionException(setMethodName + " has non-void return type"); - } - } catch(NoSuchMethodException E) { - } - } - } else if(setMethodName != null) { - Method[] m = beanClass.getMethods(); - for(int i=0;i<m.length;i++) { - Method current = m[i]; - if(current.getName().equals(setMethodName) - && current.getParameterTypes().length == 1 - && current.getReturnType().equals(java.lang.Void.TYPE)) { - if(setMethod != null) { - throw new IntrospectionException("Multiple, different set methods found that fit the bill!"); - } else { - setMethod = current; - propertyType = current.getParameterTypes()[0]; - } - } - } - if(setMethod == null) { - throw new IntrospectionException("Cannot find get or set methods."); - } - } else { - throw new IntrospectionException("Cannot find get or set methods."); - } - } catch(SecurityException E) { - throw new IntrospectionException("SecurityException thrown on attempt to access methods."); - } + if ((!getMethod.getDeclaringClass(). + isAssignableFrom(setMethod.getDeclaringClass())) && + (!setMethod.getDeclaringClass(). + isAssignableFrom(getMethod.getDeclaringClass()))) { + String msg = "set and get methods are not in the same class."; + throw new IntrospectionException(msg); } + } + } + } } |