/[classpath]/classpath/java/beans/PropertyDescriptor.java
ViewVC logotype

Diff of /classpath/java/beans/PropertyDescriptor.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.10 by uid67440, Fri Dec 26 19:39:54 2003 UTC revision 1.11 by rschuster, Sat Nov 13 00:08:14 2004 UTC
# Line 1  Line 1 
1  /* java.beans.PropertyDescriptor  /* java.beans.PropertyDescriptor
2     Copyright (C) 1998, 2001 Free Software Foundation, Inc.     Copyright (C) 1998, 2001, 2004 Free Software Foundation, Inc.
3    
4  This file is part of GNU Classpath.  This file is part of GNU Classpath.
5    
# Line 35  this exception to your version of the li Line 35  this exception to your version of the li
35  obligated to do so.  If you do not wish to do so, delete this  obligated to do so.  If you do not wish to do so, delete this
36  exception statement from your version. */  exception statement from your version. */
37    
   
38  package java.beans;  package java.beans;
39    
40  import java.lang.reflect.Method;  import java.lang.reflect.Method;
# Line 58  import java.lang.reflect.Method; Line 57  import java.lang.reflect.Method;
57   ** </OL>   ** </OL>
58   **   **
59   ** @author John Keiser   ** @author John Keiser
60   ** @since JDK1.1   ** @author Robert Schuster <thebohemian@gmx.net>
61   ** @version 1.1.0, 26 Jul 1998   ** @since 1.1
62     ** @status updated to 1.4
63   **/   **/
64    
65  public class PropertyDescriptor extends FeatureDescriptor {  public class PropertyDescriptor extends FeatureDescriptor
66    Class propertyType;  {
67    Method getMethod;      Class propertyType;
68    Method setMethod;      Method getMethod;
69          Method setMethod;
70    Class propertyEditorClass;  
71    boolean bound;      Class propertyEditorClass;
72    boolean constrained;      boolean bound;
73          boolean constrained;
74    PropertyDescriptor(String name) {  
75      setName(name);      PropertyDescriptor(String name)
76    }      {
77              setName(name);
78    /** Create a new PropertyDescriptor by introspection.      }
79     ** This form of constructor creates the PropertyDescriptor by  
80     ** looking for a getter method named <CODE>get&lt;name&gt;()</CODE>      /** Create a new PropertyDescriptor by introspection.
81     ** (or, optionally, if the property is boolean,       ** This form of constructor creates the PropertyDescriptor by
82     ** <CODE>is&lt;name&gt;()</CODE>) and       ** looking for a getter method named <CODE>get&lt;name&gt;()</CODE>
83     ** <CODE>set&lt;name&gt;()</CODE> in class       ** (or, optionally, if the property is boolean,
84     ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its       ** <CODE>is&lt;name&gt;()</CODE>) and
85     ** first letter capitalized by the constructor.<P>       ** <CODE>set&lt;name&gt;()</CODE> in class
86     **       ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its
87     ** <B>Implementation note:</B> If there is both are both isXXX and       ** first letter capitalized by the constructor.<P>
88     ** getXXX methods, the former is used in preference to the latter.       **
89     ** We do not check that an isXXX method returns a boolean. In both       ** Note that using this constructor the given property must be read- <strong>and</strong>
90     ** cases, this matches the behaviour of JDK 1.4<P>       ** writeable. If the implementation does not both, a read and a write method, an
91     **       ** <code>IntrospectionException</code> is thrown.
92     ** @param name the programmatic name of the property, usually       **
93     **             starting with a lowercase letter (e.g. fooManChu       ** <B>Implementation note:</B> If there is both are both isXXX and
94     **             instead of FooManChu).       ** getXXX methods, the former is used in preference to the latter.
95     ** @param beanClass the class the get and set methods live in.       ** We do not check that an isXXX method returns a boolean. In both
96     ** @exception IntrospectionException if the methods are not found       ** cases, this matches the behaviour of JDK 1.4<P>
97     **            or invalid.       **
98     **/       ** @param name the programmatic name of the property, usually
99    public PropertyDescriptor(String name, Class beanClass)       **             starting with a lowercase letter (e.g. fooManChu
100      throws IntrospectionException       **             instead of FooManChu).
101    {       ** @param beanClass the class the get and set methods live in.
102      setName(name);       ** @exception IntrospectionException if the methods are not found
103      if (name.length() == 0) {       **            or invalid.
104        throw new IntrospectionException("empty property name");       **/
105      }      public PropertyDescriptor(String name, Class beanClass)
106      String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1);          throws IntrospectionException
107      findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps);      {
108      if (getMethod == null) {          setName(name);
109        throw new IntrospectionException("Cannot find an is" + caps +          if (name.length() == 0)
110                                         " or get" + caps + " method");          {
111      }              throw new IntrospectionException("empty property name");
112      if (setMethod == null) {          }
113        throw new IntrospectionException("Cannot find a " + caps + " method");          String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1);
114      }          findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps);
115      checkMethods();  
116    }          if (getMethod == null)
117              {
118    /** Create a new PropertyDescriptor by introspection.              throw new IntrospectionException(
119     ** This form of constructor allows you to specify the                  "Cannot find a is" + caps + " or get" + caps + " method");
120     ** names of the get and set methods to search for.<P>          }
121     **  
122     ** <B>Implementation note:</B> If there is a get method (or          if (setMethod == null)
123     ** boolean isXXX() method), then the return type of that method          {
124     ** is used to find the set method.  If there is no get method,              throw new IntrospectionException(
125     ** then the set method is searched for exhaustively.<P>                  "Cannot find a " + caps + " method");
126     **          }
127     ** <B>Spec note:</B>  
128     ** If there is no get method and multiple set methods with          // finally check the methods compatibility        
129     ** the same name and a single parameter (different type of course),          checkMethods(getMethod, setMethod);
130     ** then an IntrospectionException is thrown.  While Sun's spec      }
131     ** does not state this, it can make Bean behavior different on  
132     ** different systems (since method order is not guaranteed) and as      /** Create a new PropertyDescriptor by introspection.
133     ** such, can be treated as a bug in the spec.  I am not aware of       ** This form of constructor allows you to specify the
134     ** whether Sun's implementation catches this.       ** names of the get and set methods to search for.<P>
135     **       **
136     ** @param name the programmatic name of the property, usually       ** <B>Implementation note:</B> If there is a get method (or
137     **             starting with a lowercase letter (e.g. fooManChu       ** boolean isXXX() method), then the return type of that method
138     **             instead of FooManChu).       ** is used to find the set method.  If there is no get method,
139     ** @param beanClass the class the get and set methods live in.       ** then the set method is searched for exhaustively.<P>
140     ** @param getMethodName the name of the get method.       **
141     ** @param setMethodName the name of the set method.       ** <B>Spec note:</B>
142     ** @exception IntrospectionException if the methods are not found       ** If there is no get method and multiple set methods with
143     **            or invalid.       ** the same name and a single parameter (different type of course),
144     **/       ** then an IntrospectionException is thrown.  While Sun's spec
145    public PropertyDescriptor(String name, Class beanClass,       ** does not state this, it can make Bean behavior different on
146                              String getMethodName, String setMethodName)       ** different systems (since method order is not guaranteed) and as
147      throws IntrospectionException       ** such, can be treated as a bug in the spec.  I am not aware of
148    {       ** whether Sun's implementation catches this.
149      setName(name);       **
150      findMethods(beanClass, getMethodName, null, setMethodName);       ** @param name the programmatic name of the property, usually
151      if (getMethod == null && getMethodName != null) {       **             starting with a lowercase letter (e.g. fooManChu
152        throw new IntrospectionException("Cannot find a getter method called " +       **             instead of FooManChu).
153                                         getMethodName);       ** @param beanClass the class the get and set methods live in.
154      }       ** @param getMethodName the name of the get method or <code>null</code> if the property is write-only.
155      if (setMethod == null && setMethodName != null) {       ** @param setMethodName the name of the set method or <code>null</code> if the property is read-only.
156        throw new IntrospectionException("Cannot find a setter method called " +       ** @exception IntrospectionException if the methods are not found
157                                         setMethodName);       **            or invalid.
158      }       **/
159      checkMethods();      public PropertyDescriptor(
160    }          String name,
161              Class beanClass,
162    /** Create a new PropertyDescriptor using explicit Methods.          String getMethodName,
163     ** Note that the methods will be checked for conformance to standard          String setMethodName)
164     ** Property method rules, as described above at the top of this class.          throws IntrospectionException
165     **      {
166     ** @param name the programmatic name of the property, usually          setName(name);
167     **             starting with a lowercase letter (e.g. fooManChu          findMethods(beanClass, getMethodName, null, setMethodName);
168     **             instead of FooManChu).  
169     ** @param getMethod the get method.          if (getMethod == null && getMethodName != null)
170     ** @param setMethod the set method.          {
171     ** @exception IntrospectionException if the methods are not found              throw new IntrospectionException(
172     **            or invalid.                  "Cannot find a getter method called " + getMethodName);
173     **/          }
174    public PropertyDescriptor(String name, Method getMethod, Method setMethod)  
175      throws IntrospectionException          if (setMethod == null && setMethodName != null)
176    {          {
177      setName(name);              throw new IntrospectionException(
178      this.getMethod = getMethod;                  "Cannot find a setter method called " + setMethodName);
179      this.setMethod = setMethod;          }
180      if (getMethod != null) {  
181        this.propertyType = getMethod.getReturnType();          checkMethods(getMethod, setMethod);
182      }      }
183      else if (setMethod != null) {  
184        this.propertyType = setMethod.getParameterTypes()[0];      /** Create a new PropertyDescriptor using explicit Methods.
185      }       ** Note that the methods will be checked for conformance to standard
186      checkMethods();       ** Property method rules, as described above at the top of this class.
187    }       **<br>
188           ** It is possible to call this method with both <code>Method</code> arguments
189    /** Get the property type.       ** being <code>null</code>. In such a case the property type is <code>null</code>.
190     ** This is the type the get method returns and the set method       **
191     ** takes in.       ** @param name the programmatic name of the property, usually
192     **/       **             starting with a lowercase letter (e.g. fooManChu
193    public Class getPropertyType() {       **             instead of FooManChu).
194      return propertyType;       ** @param readMethod the read method or <code>null</code> if the property is write-only.
195    }       ** @param writeMethod the write method or <code>null</code> if the property is read-only.
196           ** @exception IntrospectionException if the methods are not found
197    /** Get the get method.  Why they call it readMethod here and       **            or invalid.
198     ** get everywhere else is beyond me.       **/
199     **/      public PropertyDescriptor(
200    public Method getReadMethod() {          String name,
201      return getMethod;          Method readMethod,
202    }          Method writeMethod)
203              throws IntrospectionException
204    /** Get the set method.  Why they call it writeMethod here and      {
205     ** set everywhere else is beyond me.          setName(name);
206     **/          getMethod = readMethod;
207    public Method getWriteMethod() {          setMethod = writeMethod;
208      return setMethod;  
209    }          if (getMethod != null)
210              {
211    /** Get whether the property is bound.  Defaults to false. **/              this.propertyType = getMethod.getReturnType();
212    public boolean isBound() {          }
213      return bound;          else if (setMethod != null)
214    }          {
215                  this.propertyType = setMethod.getParameterTypes()[0];
216    /** Set whether the property is bound.          }
217     ** As long as the the bean implements addPropertyChangeListener() and  
218     ** removePropertyChangeListener(), setBound(true) may safely be called.<P>          checkMethods(getMethod, setMethod);
219     ** If these things are not true, then the behavior of the system      }
220     ** will be undefined.<P>  
221     **      /** Get the property type.
222     ** When a property is bound, its set method is required to fire the       ** This is the type the get method returns and the set method
223     ** <CODE>PropertyChangeListener.propertyChange())</CODE> event       ** takes in.
224     ** after the value has changed.       **/
225     ** @param bound whether the property is bound or not.      public Class getPropertyType()
226     **/      {
227    public void setBound(boolean bound) {          return propertyType;
228      this.bound = bound;      }
229    }  
230          /** Get the get method.  Why they call it readMethod here and
231    /** Get whether the property is constrained.  Defaults to false. **/       ** get everywhere else is beyond me.
232    public boolean isConstrained() {       **/
233      return constrained;      public Method getReadMethod()
234    }      {
235              return getMethod;
236    /** Set whether the property is constrained.      }
237     ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE>  
238     ** (or subclass thereof) and the bean implements addVetoableChangeListener()      /** Sets the read method.<br/>
239     ** and removeVetoableChangeListener(), then setConstrained(true) may safely       * The read method is used to retrieve the value of a property. A legal
240     ** be called.  Otherwise, the system behavior is undefined.       * read method must have no arguments. Its return type must not be
241     ** <B>Spec note:</B> given those strict parameters, it would be nice if it       * <code>void</code>. If this methods succeeds the property type
242     ** got set automatically by detection, but oh well.<P>       * is adjusted to the return type of the read method.<br/>
243     ** When a property is constrained, its set method is required to:<P>       * <br/>
244     ** <OL>       * It is legal to set the read and the write method to <code>null</code>
245     ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE>       * or provide method which have been declared in distinct classes.
246     **     event notifying others of the change and allowing them a chance to       *
247     **     say it is a bad thing.</LI>       * @param readMethod The new method to be used or <code>null</code>.
248     ** <LI>If any of the listeners throws a PropertyVetoException, then       * @throws IntrospectionException If the given method is invalid.
249     **     it must fire another vetoableChange() event notifying the others       * @since 1.2
250     **     of a reversion to the old value (though, of course, the change       */
251     **     was never made).  Then it rethrows the PropertyVetoException and      public void setReadMethod(Method readMethod) throws IntrospectionException
252     **     exits.</LI>      {
253     ** <LI>If all has gone well to this point, the value may be changed.</LI>          checkMethods(readMethod, setMethod);
254     ** </OL>  
255     ** @param constrained whether the property is constrained or not.          getMethod = readMethod;
256     **/      }
257    public void setConstrained(boolean constrained) {  
258      this.constrained = constrained;      /** Get the set method.  Why they call it writeMethod here and
259    }       ** set everywhere else is beyond me.
260           **/
261    /** Get the PropertyEditor class.  Defaults to null. **/      public Method getWriteMethod()
262    public Class getPropertyEditorClass() {      {
263      return propertyEditorClass;          return setMethod;
264    }      }
265      
266    /** Set the PropertyEditor class.  If the class does not implement      /** Sets the write method.<br/>
267     ** the PropertyEditor interface, you will likely get an exception       * The write method is used to set the value of a property. A legal write method
268     ** late in the game.       * must have a single argument which can be assigned to the property. If no
269     ** @param propertyEditorClass the PropertyEditor class for this       * read method exists the property type changes to the argument type of the
270     **        class to use.       * write method.<br/>
271     **/       * <br/>
272    public void setPropertyEditorClass(Class propertyEditorClass) {       * It is legal to set the read and the write method to <code>null</code>
273      this.propertyEditorClass = propertyEditorClass;       * or provide method which have been declared in distinct classes.
274    }       *
275           * @param writeMethod The new method to be used or <code>null</code>.
276    private void findMethods(Class beanClass, String getMethodName1,       * @throws IntrospectionException If the given method is invalid.
277                             String getMethodName2, String setMethodName)       * @since 1.2
278      throws IntrospectionException       */
279    {      public void setWriteMethod(Method writeMethod)
280      try {          throws IntrospectionException
281        // Try the first get method name      {
282        if (getMethodName1 != null) {          propertyType = checkMethods(getMethod, writeMethod);
283          try {  
284            getMethod = beanClass.getMethod(getMethodName1, new Class[0]);          setMethod = writeMethod;
         }  
         catch (NoSuchMethodException e) {  
         }  
       }  
   
       // Fall back to the second get method name  
       if (getMethod == null && getMethodName2 != null) {  
         try {  
           getMethod = beanClass.getMethod(getMethodName2, new Class[0]);  
         }  
         catch (NoSuchMethodException e) {  
         }  
       }  
   
       // 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) {  
           }  
         }  
         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);  
     }  
   }  
   
   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);  
         }  
         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);  
         }  
       }  
285      }      }
286    }  
287        /** Get whether the property is bound.  Defaults to false. **/
288        public boolean isBound()
289        {
290            return bound;
291        }
292    
293        /** Set whether the property is bound.
294         ** As long as the the bean implements addPropertyChangeListener() and
295         ** removePropertyChangeListener(), setBound(true) may safely be called.<P>
296         ** If these things are not true, then the behavior of the system
297         ** will be undefined.<P>
298         **
299         ** When a property is bound, its set method is required to fire the
300         ** <CODE>PropertyChangeListener.propertyChange())</CODE> event
301         ** after the value has changed.
302         ** @param bound whether the property is bound or not.
303         **/
304        public void setBound(boolean bound)
305        {
306            this.bound = bound;
307        }
308    
309        /** Get whether the property is constrained.  Defaults to false. **/
310        public boolean isConstrained()
311        {
312            return constrained;
313        }
314    
315        /** Set whether the property is constrained.
316         ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE>
317         ** (or subclass thereof) and the bean implements addVetoableChangeListener()
318         ** and removeVetoableChangeListener(), then setConstrained(true) may safely
319         ** be called.  Otherwise, the system behavior is undefined.
320         ** <B>Spec note:</B> given those strict parameters, it would be nice if it
321         ** got set automatically by detection, but oh well.<P>
322         ** When a property is constrained, its set method is required to:<P>
323         ** <OL>
324         ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE>
325         **     event notifying others of the change and allowing them a chance to
326         **     say it is a bad thing.</LI>
327         ** <LI>If any of the listeners throws a PropertyVetoException, then
328         **     it must fire another vetoableChange() event notifying the others
329         **     of a reversion to the old value (though, of course, the change
330         **     was never made).  Then it rethrows the PropertyVetoException and
331         **     exits.</LI>
332         ** <LI>If all has gone well to this point, the value may be changed.</LI>
333         ** </OL>
334         ** @param constrained whether the property is constrained or not.
335         **/
336        public void setConstrained(boolean constrained)
337        {
338            this.constrained = constrained;
339        }
340    
341        /** Get the PropertyEditor class.  Defaults to null. **/
342        public Class getPropertyEditorClass()
343        {
344            return propertyEditorClass;
345        }
346    
347        /** Set the PropertyEditor class.  If the class does not implement
348         ** the PropertyEditor interface, you will likely get an exception
349         ** late in the game.
350         ** @param propertyEditorClass the PropertyEditor class for this
351         **        class to use.
352         **/
353        public void setPropertyEditorClass(Class propertyEditorClass)
354        {
355            this.propertyEditorClass = propertyEditorClass;
356        }
357    
358        private void findMethods(
359            Class beanClass,
360            String getMethodName1,
361            String getMethodName2,
362            String setMethodName)
363            throws IntrospectionException
364        {
365            try
366            {
367                // Try the first get method name
368                if (getMethodName1 != null)
369                {
370                    try
371                    {
372                        getMethod =
373                            beanClass.getMethod(getMethodName1, new Class[0]);
374                    }
375                    catch (NoSuchMethodException e)
376                    {}
377                }
378    
379                // Fall back to the second get method name
380                if (getMethod == null && getMethodName2 != null)
381                {
382                    try
383                    {
384                        getMethod =
385                            beanClass.getMethod(getMethodName2, new Class[0]);
386                    }
387                    catch (NoSuchMethodException e)
388                    {}
389                }
390    
391                // Try the set method name
392                if (setMethodName != null)
393                {
394                    if (getMethod != null)
395                    {
396                        // If there is a get method, use its return type to help
397                        // select the corresponding set method.
398                        Class propertyType = getMethod.getReturnType();
399                        if (propertyType == Void.TYPE)
400                        {
401                            String msg =
402                                "The property's read method has return type 'void'";
403                            throw new IntrospectionException(msg);
404                        }
405    
406                        Class[] setArgs = new Class[] { propertyType };
407                        try
408                        {
409                            setMethod = beanClass.getMethod(setMethodName, setArgs);
410                        }
411                        catch (NoSuchMethodException e)
412                        {}
413                    }
414                    else if (getMethodName1 == null && getMethodName2 == null)
415                    {
416                        // If this is a write-only property, choose the first set method
417                        // with the required name, one parameter and return type 'void'
418                        Method[] methods = beanClass.getMethods();
419                        for (int i = 0; i < methods.length; i++)
420                        {
421                            if (methods[i].getName().equals(setMethodName)
422                                && methods[i].getParameterTypes().length == 1
423                                && methods[i].getReturnType() == Void.TYPE)
424                            {
425                                setMethod = methods[i];
426                                break;
427                            }
428                        }
429                    }
430                }
431            }
432            catch (SecurityException e)
433            {
434                // FIXME -- shouldn't we just allow SecurityException to propagate?
435                String msg =
436                    "SecurityException thrown on attempt to access methods.";
437                throw new IntrospectionException(msg);
438            }
439        }
440    
441        /** Checks whether the given <code>Method</code> instances are legal read and
442         * write methods. The following requirements must be met:<br/>
443         * <ul>
444         * <li>the read method must not have an argument</li>
445         * <li>the read method must have a non void return type</li>
446         * <li>the read method may not exist</li>
447         * <li>the write method must have a single argument</li>
448         * <li>the property type and the read method's return type must be assignable from the
449         * write method's argument type</li>
450         * <li>the write method may not exist</li>
451         * <ul>
452         * While checking the methods a common new property type is calculated. If the method
453         * succeeds this property type is returned.<br/>
454         * <br/>
455         * For compatibility this has to be noted:<br/>
456         * The two methods are allowed to be defined in two distinct classes and may both be null.
457         *
458         * @param readMethod The new read method to check.
459         * @param writeMethod The new write method to check.
460         * @return The common property type of the two method.
461         * @throws IntrospectionException If any of the above requirements are not met.
462         */
463        private Class checkMethods(Method readMethod, Method writeMethod)
464            throws IntrospectionException
465        {
466            Class newPropertyType = propertyType;
467    
468            // a valid read method has zero arguments and a non-void return type.
469            if (readMethod != null)
470            {
471                if (readMethod.getParameterTypes().length > 0)
472                {
473                    throw new IntrospectionException("read method has unexpected parameters");
474                }
475    
476                newPropertyType = readMethod.getReturnType();
477    
478                if (newPropertyType == Void.TYPE)
479                {
480                    throw new IntrospectionException("read method return type is void");
481                }
482            }
483    
484            // a valid write method has one argument which can be assigned to the property
485            if (writeMethod != null)
486            {
487                if (writeMethod.getParameterTypes().length != 1)
488                {
489                    String msg = "write method does not have exactly one parameter";
490                    throw new IntrospectionException(msg);
491                }
492    
493                if (readMethod == null)
494                {
495                    // changes the property type if there is no read method
496                    newPropertyType = writeMethod.getParameterTypes()[0];
497                }
498                else
499                {
500                    // checks whether the write method can be assigned to the return type of the read
501                    // method (if this is not the case, the methods are not compatible)
502                    // note: newPropertyType may be null if no methods or method names have been
503                    // delivered in the constructor.
504                    if (newPropertyType != null
505                        && !newPropertyType.isAssignableFrom(
506                            writeMethod.getParameterTypes()[0]))
507                    {
508                        // note: newPropertyType is the same as readMethod.getReturnType() at this point
509                        throw new IntrospectionException("read and write method are not compatible");
510                    }
511    
512                    /* note: the check whether both method are defined in related classes makes sense but is not
513                     * done in the JDK.
514                     * I leave this code here in case someone at Sun decides to add that functionality in later versions (rschuster)
515                    if ((!readMethod
516                        .getDeclaringClass()
517                        .isAssignableFrom(writeMethod.getDeclaringClass()))
518                        && (!writeMethod
519                            .getDeclaringClass()
520                            .isAssignableFrom(readMethod.getDeclaringClass())))
521                    {
522                        String msg =
523                            "set and get methods are not in the same class.";
524                        throw new IntrospectionException(msg);
525                    }
526                    */
527    
528                }
529            }
530    
531            return newPropertyType;
532        }
533    
534        /** Compares this <code>PropertyDescriptor</code> against the
535         * given object.
536         * Two PropertyDescriptors are equals if
537         * <ul>
538         * <li>the read methods are equal</li>
539         * <li>the write methods are equal</li>
540         * <li>the property types are equals</li>
541         * <li>the property editor classes are equal</li>
542         * <li>the flags (constrained and bound) are equal</li>
543         * </ul>
544         * @return Whether both objects are equal according to the rules given above.
545         * @since 1.4
546        */
547        public boolean equals(Object o)
548        {
549            if (o instanceof PropertyDescriptor)
550            {
551                PropertyDescriptor that = (PropertyDescriptor) o;
552    
553                // compares the property types and checks the case where both are null
554                boolean samePropertyType =
555                    (propertyType == null)
556                        ? that.propertyType == null
557                        : propertyType.equals(that.propertyType);
558    
559                // compares the property editor classes and checks the case where both are null
560                boolean samePropertyEditorClass =
561                    (propertyEditorClass == null)
562                        ? that.propertyEditorClass == null
563                        : propertyEditorClass.equals(that.propertyEditorClass);
564    
565                // compares the flags for equality
566                boolean sameFlags =
567                    bound == that.bound && constrained == that.constrained;
568    
569                // compares the read methods and checks the case where both are null
570                boolean sameReadMethod =
571                    (getMethod == null)
572                        ? that.getMethod == null
573                        : getMethod.equals(that.getMethod);
574    
575                boolean sameWriteMethod =
576                    (setMethod == null)
577                        ? that.setMethod == null
578                        : setMethod.equals(that.setMethod);
579    
580                return samePropertyType
581                    && sameFlags
582                    && sameReadMethod
583                    && sameWriteMethod
584                    && samePropertyEditorClass;
585            }
586            else
587            {
588                return false;
589            }
590            
591        }
592    
593  }  }

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.11

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26