OSDN Git Service

Stephen Crawley <crawley@dstc.edu.au>
authormark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 7 Feb 2003 20:19:53 +0000 (20:19 +0000)
committermark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 7 Feb 2003 20:19:53 +0000 (20:19 +0000)
       * 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@62537 138bc75d-0d04-0410-961f-82ee72b054a4

libjava/ChangeLog
libjava/java/beans/PropertyDescriptor.java

index 173c85e..32167d5 100644 (file)
@@ -1,3 +1,18 @@
+2003-02-07  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.
+
 2003-02-04  Tom Tromey  <tromey@redhat.com>
 
        * java/io/PipedOutputStream.java (flush): Declare as throwing
index b75cac9..00db416 100644 (file)
@@ -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&lt;name&gt;()</CODE>
-        ** (or, optionally, if the property is boolean,
-        ** <CODE>is&lt;name&gt;()</CODE>) and
-        ** <CODE>set&lt;name&gt;()</CODE> in class
-        ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; 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&lt;name&gt;()</CODE>
+   ** (or, optionally, if the property is boolean,
+   ** <CODE>is&lt;name&gt;()</CODE>) and
+   ** <CODE>set&lt;name&gt;()</CODE> in class
+   ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; 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);
        }
+      }
+    }
+  }
 }