/[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.7 by mark, Tue Jan 22 22:26:59 2002 UTC revision 1.8 by mark, Fri Feb 7 16:13:54 2003 UTC
# Line 65  import java.lang.reflect.*; Line 65  import java.lang.reflect.*;
65   **/   **/
66    
67  public class PropertyDescriptor extends FeatureDescriptor {  public class PropertyDescriptor extends FeatureDescriptor {
68          Class propertyType;    Class propertyType;
69          Method getMethod;    Method getMethod;
70          Method setMethod;    Method setMethod;
71      
72          Class propertyEditorClass;    Class propertyEditorClass;
73          boolean bound;    boolean bound;
74          boolean constrained;    boolean constrained;
75      
76          PropertyDescriptor(String name) {    PropertyDescriptor(String name) {
77                  setName(name);      setName(name);
78          }    }
79      
80          /** Create a new PropertyDescriptor by introspection.    /** Create a new PropertyDescriptor by introspection.
81           ** This form of constructor creates the PropertyDescriptor by     ** This form of constructor creates the PropertyDescriptor by
82           ** looking for a getter method named <CODE>get&lt;name&gt;()</CODE>     ** looking for a getter method named <CODE>get&lt;name&gt;()</CODE>
83           ** (or, optionally, if the property is boolean,     ** (or, optionally, if the property is boolean,
84           ** <CODE>is&lt;name&gt;()</CODE>) and     ** <CODE>is&lt;name&gt;()</CODE>) and
85           ** <CODE>set&lt;name&gt;()</CODE> in class     ** <CODE>set&lt;name&gt;()</CODE> in class
86           ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its     ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its
87           ** first letter capitalized by the constructor.<P>     ** first letter capitalized by the constructor.<P>
88           **     **
89           ** <B>Implementation note:</B> If there is a get method (or     ** <B>Implementation note:</B> If there is a get method (or
90           ** boolean isXXX() method), then the return type of that method     ** boolean isXXX() method), then the return type of that method
91           ** is used to find the set method.  If there is no get method,     ** is used to find the set method.  If there is no get method,
92           ** then the set method is searched for exhaustively.<P>     ** then the set method is searched for exhaustively.<P>
93           **     **
94           ** <B>Spec note:</B>     ** <B>Spec note:</B>
95           ** If there is no get method and multiple set methods with     ** If there is no get method and multiple set methods with
96           ** the same name and a single parameter (different type of course),     ** the same name and a single parameter (different type of course),
97           ** then an IntrospectionException is thrown.  While Sun's spec     ** then an IntrospectionException is thrown.  While Sun's spec
98           ** does not state this, it can make Bean behavior different on     ** does not state this, it can make Bean behavior different on
99           ** different systems (since method order is not guaranteed) and as     ** different systems (since method order is not guaranteed) and as
100           ** such, can be treated as a bug in the spec.  I am not aware of     ** such, can be treated as a bug in the spec.  I am not aware of
101           ** whether Sun's implementation catches this.     ** whether Sun's implementation catches this.
102           **     **
103           ** @param name the programmatic name of the property, usually     ** @param name the programmatic name of the property, usually
104           **             starting with a lowercase letter (e.g. fooManChu     **             starting with a lowercase letter (e.g. fooManChu
105           **             instead of FooManChu).     **             instead of FooManChu).
106           ** @param beanClass the class the get and set methods live in.     ** @param beanClass the class the get and set methods live in.
107           ** @exception IntrospectionException if the methods are not found or invalid.     ** @exception IntrospectionException if the methods are not found or invalid.
108           **/     **/
109          public PropertyDescriptor(String name, Class beanClass) throws IntrospectionException {    public PropertyDescriptor(String name, Class beanClass)
110                  setName(name);      throws IntrospectionException
111                  String capitalized;    {
112                  try {      setName(name);
113                          capitalized = Character.toUpperCase(name.charAt(0)) + name.substring(1);      String capitalized;
114                  } catch(StringIndexOutOfBoundsException e) {      try {
115                          capitalized = "";        capitalized = Character.toUpperCase(name.charAt(0)) + name.substring(1);
116                  }      }
117                  findMethods(beanClass, "is" + capitalized, "get" + capitalized, "set" + capitalized);      catch (StringIndexOutOfBoundsException e) {
118          }        capitalized = "";
119        }
120          /** Create a new PropertyDescriptor by introspection.      findMethods(beanClass, "is" + capitalized, "get" + capitalized,
121           ** This form of constructor allows you to specify the                  "set" + capitalized);
122           ** names of the get and set methods to search for.<P>    }
123           **    
124           ** <B>Implementation note:</B> If there is a get method (or    /** Create a new PropertyDescriptor by introspection.
125           ** boolean isXXX() method), then the return type of that method     ** This form of constructor allows you to specify the
126           ** is used to find the set method.  If there is no get method,     ** names of the get and set methods to search for.<P>
127           ** then the set method is searched for exhaustively.<P>     **
128           **     ** <B>Implementation note:</B> If there is a get method (or
129           ** <B>Spec note:</B>     ** boolean isXXX() method), then the return type of that method
130           ** If there is no get method and multiple set methods with     ** is used to find the set method.  If there is no get method,
131           ** the same name and a single parameter (different type of course),     ** then the set method is searched for exhaustively.<P>
132           ** then an IntrospectionException is thrown.  While Sun's spec     **
133           ** does not state this, it can make Bean behavior different on     ** <B>Spec note:</B>
134           ** different systems (since method order is not guaranteed) and as     ** If there is no get method and multiple set methods with
135           ** such, can be treated as a bug in the spec.  I am not aware of     ** the same name and a single parameter (different type of course),
136           ** whether Sun's implementation catches this.     ** then an IntrospectionException is thrown.  While Sun's spec
137           **     ** does not state this, it can make Bean behavior different on
138           ** @param name the programmatic name of the property, usually     ** different systems (since method order is not guaranteed) and as
139           **             starting with a lowercase letter (e.g. fooManChu     ** such, can be treated as a bug in the spec.  I am not aware of
140           **             instead of FooManChu).     ** whether Sun's implementation catches this.
141           ** @param beanClass the class the get and set methods live in.     **
142           ** @param getMethodName the name of the get method.     ** @param name the programmatic name of the property, usually
143           ** @param setMethodName the name of the set method.     **             starting with a lowercase letter (e.g. fooManChu
144           ** @exception IntrospectionException if the methods are not found or invalid.     **             instead of FooManChu).
145           **/     ** @param beanClass the class the get and set methods live in.
146          public PropertyDescriptor(String name, Class beanClass, String getMethodName, String setMethodName) throws IntrospectionException {     ** @param getMethodName the name of the get method.
147                  setName(name);     ** @param setMethodName the name of the set method.
148                  findMethods(beanClass, getMethodName, null, setMethodName);     ** @exception IntrospectionException if the methods are not found
149          }     **            or invalid.
150       **/
151          /** Create a new PropertyDescriptor using explicit Methods.    public PropertyDescriptor(String name, Class beanClass,
152           ** Note that the methods will be checked for conformance to standard                              String getMethodName, String setMethodName)
153           ** Property method rules, as described above at the top of this class.      throws IntrospectionException
154           **    {
155           ** @param name the programmatic name of the property, usually      setName(name);
156           **             starting with a lowercase letter (e.g. fooManChu      findMethods(beanClass, getMethodName, null, setMethodName);
157           **             instead of FooManChu).    }
158           ** @param getMethod the get method.    
159           ** @param setMethod the set method.    /** Create a new PropertyDescriptor using explicit Methods.
160           ** @exception IntrospectionException if the methods are not found or invalid.     ** Note that the methods will be checked for conformance to standard
161           **/     ** Property method rules, as described above at the top of this class.
162          public PropertyDescriptor(String name, Method getMethod, Method setMethod) throws IntrospectionException {     **
163                  setName(name);     ** @param name the programmatic name of the property, usually
164                  if(getMethod != null && getMethod.getParameterTypes().length > 0) {     **             starting with a lowercase letter (e.g. fooManChu
165                          throw new IntrospectionException("get method has parameters");     **             instead of FooManChu).
166                  }     ** @param getMethod the get method.
167                  if(setMethod != null && setMethod.getParameterTypes().length != 1) {     ** @param setMethod the set method.
168                          throw new IntrospectionException("set method does not have exactly one parameter");     ** @exception IntrospectionException if the methods are not found
169                  }     **            or invalid.
170                  if(getMethod != null && setMethod != null) {     **/
171                          if(!getMethod.getReturnType().equals(setMethod.getParameterTypes()[0])) {    public PropertyDescriptor(String name, Method getMethod, Method setMethod)
172                                  throw new IntrospectionException("set and get methods do not share the same type");      throws IntrospectionException
173                          }    {
174                          if(!getMethod.getDeclaringClass().isAssignableFrom(setMethod.getDeclaringClass())      setName(name);
175                             && !setMethod.getDeclaringClass().isAssignableFrom(getMethod.getDeclaringClass())) {      if (getMethod != null && getMethod.getParameterTypes().length > 0) {
176                                  throw new IntrospectionException("set and get methods are not in the same class.");        throw new IntrospectionException("get method has parameters");
177                          }      }
178                  }      if (setMethod != null && setMethod.getParameterTypes().length != 1) {
179                  this.getMethod = getMethod;        String msg = "set method does not have exactly one parameter";
180                  this.setMethod = setMethod;        throw new IntrospectionException(msg);
181                  if(getMethod != null) {      }
182                          this.propertyType = getMethod.getReturnType();      if (getMethod != null && setMethod != null) {
183                  } else {        if (!getMethod.getReturnType().
184                          this.propertyType = setMethod.getParameterTypes()[0];            equals(setMethod.getParameterTypes()[0])) {
185                  }          String msg = "set and get methods do not share the same type";
186          }          throw new IntrospectionException(msg);
187          }
188          /** Get the property type.        if ((!getMethod.getDeclaringClass().
189           ** This is the type the get method returns and the set method             isAssignableFrom(setMethod.getDeclaringClass())) &&
190           ** takes in.            (!setMethod.getDeclaringClass().
191           **/             isAssignableFrom(getMethod.getDeclaringClass()))) {
192          public Class getPropertyType() {          String msg = "set and get methods are not in the same class.";
193                  return propertyType;          throw new IntrospectionException(msg);
194          }        }
195        }
196          /** Get the get method.  Why they call it readMethod here and      this.getMethod = getMethod;
197           ** get everywhere else is beyond me.      this.setMethod = setMethod;
198           **/      if (getMethod != null) {
199          public Method getReadMethod() {        this.propertyType = getMethod.getReturnType();
200                  return getMethod;      }
201          }      else {
202          this.propertyType = setMethod.getParameterTypes()[0];
203          /** Get the set method.  Why they call it writeMethod here and      }
204           ** set everywhere else is beyond me.    }
205           **/    
206          public Method getWriteMethod() {    /** Get the property type.
207                  return setMethod;     ** This is the type the get method returns and the set method
208          }     ** takes in.
209       **/
210          /** Get whether the property is bound.  Defaults to false. **/    public Class getPropertyType() {
211          public boolean isBound() {      return propertyType;
212                  return bound;    }
213          }    
214      /** Get the get method.  Why they call it readMethod here and
215          /** Set whether the property is bound.     ** get everywhere else is beyond me.
216           ** As long as the the bean implements addPropertyChangeListener() and     **/
217           ** removePropertyChangeListener(), setBound(true) may safely be called.<P>    public Method getReadMethod() {
218           ** If these things are not true, then the behavior of the system      return getMethod;
219           ** will be undefined.<P>    }
220           **    
221           ** When a property is bound, its set method is required to fire the    /** Get the set method.  Why they call it writeMethod here and
222           ** <CODE>PropertyChangeListener.propertyChange())</CODE> event     ** set everywhere else is beyond me.
223           ** after the value has changed.     **/
224           ** @param bound whether the property is bound or not.    public Method getWriteMethod() {
225           **/      return setMethod;
226          public void setBound(boolean bound) {    }
227                  this.bound = bound;    
228          }    /** Get whether the property is bound.  Defaults to false. **/
229      public boolean isBound() {
230          /** Get whether the property is constrained.  Defaults to false. **/      return bound;
231          public boolean isConstrained() {    }
232                  return constrained;    
233          }    /** Set whether the property is bound.
234       ** As long as the the bean implements addPropertyChangeListener() and
235          /** Set whether the property is constrained.     ** removePropertyChangeListener(), setBound(true) may safely be called.<P>
236           ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE>     ** If these things are not true, then the behavior of the system
237           ** (or subclass thereof) and the bean implements addVetoableChangeListener()     ** will be undefined.<P>
238           ** and removeVetoableChangeListener(), then setConstrained(true) may safely     **
239           ** be called.  Otherwise, the system behavior is undefined.     ** When a property is bound, its set method is required to fire the
240           ** <B>Spec note:</B> given those strict parameters, it would be nice if it     ** <CODE>PropertyChangeListener.propertyChange())</CODE> event
241           ** got set automatically by detection, but oh well.<P>     ** after the value has changed.
242           ** When a property is constrained, its set method is required to:<P>     ** @param bound whether the property is bound or not.
243           ** <OL>     **/
244           ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE>    public void setBound(boolean bound) {
245           **     event notifying others of the change and allowing them a chance to      this.bound = bound;
246           **     say it is a bad thing.</LI>    }
247           ** <LI>If any of the listeners throws a PropertyVetoException, then    
248           **     it must fire another vetoableChange() event notifying the others    /** Get whether the property is constrained.  Defaults to false. **/
249           **     of a reversion to the old value (though, of course, the change    public boolean isConstrained() {
250           **     was never made).  Then it rethrows the PropertyVetoException and      return constrained;
251           **     exits.</LI>    }
252           ** <LI>If all has gone well to this point, the value may be changed.</LI>    
253           ** </OL>    /** Set whether the property is constrained.
254           ** @param constrained whether the property is constrained or not.     ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE>
255           **/     ** (or subclass thereof) and the bean implements addVetoableChangeListener()
256          public void setConstrained(boolean constrained) {     ** and removeVetoableChangeListener(), then setConstrained(true) may safely
257                  this.constrained = constrained;     ** be called.  Otherwise, the system behavior is undefined.
258          }     ** <B>Spec note:</B> given those strict parameters, it would be nice if it
259       ** got set automatically by detection, but oh well.<P>
260          /** Get the PropertyEditor class.  Defaults to null. **/     ** When a property is constrained, its set method is required to:<P>
261          public Class getPropertyEditorClass() {     ** <OL>
262                  return propertyEditorClass;     ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE>
263          }     **     event notifying others of the change and allowing them a chance to
264       **     say it is a bad thing.</LI>
265          /** Set the PropertyEditor class.  If the class does not implement     ** <LI>If any of the listeners throws a PropertyVetoException, then
266           ** the PropertyEditor interface, you will likely get an exception     **     it must fire another vetoableChange() event notifying the others
267           ** late in the game.     **     of a reversion to the old value (though, of course, the change
268           ** @param propertyEditorClass the PropertyEditor class for this class to use.     **     was never made).  Then it rethrows the PropertyVetoException and
269           **/     **     exits.</LI>
270          public void setPropertyEditorClass(Class propertyEditorClass) {     ** <LI>If all has gone well to this point, the value may be changed.</LI>
271                  this.propertyEditorClass = propertyEditorClass;     ** </OL>
272          }     ** @param constrained whether the property is constrained or not.
273       **/
274          private void findMethods(Class beanClass, String getMethodName1, String getMethodName2, String setMethodName) throws IntrospectionException {    public void setConstrained(boolean constrained) {
275                  try {      this.constrained = constrained;
276                          if(getMethodName1 != null) {    }
277                                  try {    
278                                          getMethod = beanClass.getMethod(getMethodName1, new Class[0]);    /** Get the PropertyEditor class.  Defaults to null. **/
279                                  } catch(NoSuchMethodException E) {    public Class getPropertyEditorClass() {
280                                  }      return propertyEditorClass;
281                                  if(getMethodName2 != null) {    }
282                                          if(getMethod != null && !getMethod.getReturnType().equals(java.lang.Boolean.TYPE)) {    
283                                                  // If the is() method exists but isn't boolean, we'll just go on and look for    /** Set the PropertyEditor class.  If the class does not implement
284                                                  // an ordinary get() method.     ** the PropertyEditor interface, you will likely get an exception
285                                                  getMethod = null;     ** late in the game.
286                                          }     ** @param propertyEditorClass the PropertyEditor class for this
287       **        class to use.
288                                          Method getMethod2;     **/
289                                          try {    public void setPropertyEditorClass(Class propertyEditorClass) {
290                                                  getMethod2 = beanClass.getMethod(getMethodName2, new Class[0]);      this.propertyEditorClass = propertyEditorClass;
291                                          } catch(NoSuchMethodException E) {    }
292                                                  getMethod2 = null;    
293                                          }    private void findMethods(Class beanClass, String getMethodName1,
294                                          if(getMethod2 != null) {                             String getMethodName2, String setMethodName)
295                                                  if(getMethod != null) {      throws IntrospectionException
296                                                          if(!getMethod.getReturnType().equals(getMethod2.getReturnType())) {    {
297                                                                  throw new IntrospectionException("Both " + getMethodName1 + " and " + getMethodName2 + " exist, and have contradictory return types.");      try {
298                                                          }        if (getMethodName1 != null) {
299                                                  } else {          try {
300                                                          getMethod = getMethod2;            getMethod = beanClass.getMethod(getMethodName1, new Class[0]);
301                                                  }          }
302                                          }          catch (NoSuchMethodException E) {
303                                  }          }
304                          }          if (getMethodName2 != null) {
305              if (getMethod != null &&
306                          if(getMethod != null) {                !getMethod.getReturnType().equals(java.lang.Boolean.TYPE)) {
307                                  propertyType = getMethod.getReturnType();              // If the is() method exists but isn't boolean, we'll just
308                                  if(setMethodName != null) {              // go on and look for an ordinary get() method.
309                                          Class[] setArgs = new Class[1];              getMethod = null;
310                                          setArgs[0] = propertyType;            }
311                                          try {            
312                                                  setMethod = beanClass.getMethod(setMethodName, setArgs);            Method getMethod2;
313                                                  if(!setMethod.getReturnType().equals(java.lang.Void.TYPE)) {            try {
314                                                          throw new IntrospectionException(setMethodName + " has non-void return type");              getMethod2 = beanClass.getMethod(getMethodName2, new Class[0]);
315                                                  }            }
316                                          } catch(NoSuchMethodException E) {            catch (NoSuchMethodException E) {
317                                          }              getMethod2 = null;
318                                  }            }
319                          } else if(setMethodName != null) {            if (getMethod2 != null) {
320                                  Method[] m = beanClass.getMethods();              if (getMethod != null) {
321                                  for(int i=0;i<m.length;i++) {                if (!getMethod.getReturnType().
322                                          Method current = m[i];                    equals(getMethod2.getReturnType())) {
323                                          if(current.getName().equals(setMethodName)                  String msg = "Both " + getMethodName1 +
324                                             && current.getParameterTypes().length == 1                    " and " + getMethodName2 +
325                                             && current.getReturnType().equals(java.lang.Void.TYPE)) {                    " exist, and have contradictory return types.";
326                                                  if(setMethod != null) {                  throw new IntrospectionException(msg);
327                                                          throw new IntrospectionException("Multiple, different set methods found that fit the bill!");                }
328                                                  } else {              }
329                                                          setMethod = current;              else {
330                                                          propertyType = current.getParameterTypes()[0];                getMethod = getMethod2;
331                                                  }              }
332                                          }            }
333                                  }          }
334                                  if(setMethod == null) {        }
335                                          throw new IntrospectionException("Cannot find get or set methods.");        
336                                  }        if (getMethod != null) {
337                          } else {          propertyType = getMethod.getReturnType();
338                                  throw new IntrospectionException("Cannot find get or set methods.");          if (setMethodName != null) {
339                          }            Class[] setArgs = new Class[1];
340                  } catch(SecurityException E) {            setArgs[0] = propertyType;
341                          throw new IntrospectionException("SecurityException thrown on attempt to access methods.");            try {
342                  }              setMethod = beanClass.getMethod(setMethodName, setArgs);
343          }              if (!setMethod.getReturnType().equals(java.lang.Void.TYPE)) {
344                  throw new IntrospectionException(setMethodName +
345                                                   " has non-void return type");
346                }
347              }
348              catch (NoSuchMethodException E) {
349              }
350            }
351          }
352          else if (setMethodName != null) {
353            Method[] m = beanClass.getMethods();
354            for(int i = 0; i < m.length; i++) {
355              Method current = m[i];
356              if (current.getName().equals(setMethodName) &&
357                  current.getParameterTypes().length == 1 &&
358                  current.getReturnType().equals(java.lang.Void.TYPE)) {
359                if (setMethod != null) {
360                  String msg =
361                    "Multiple, different set methods found that fit the bill!";
362                  throw new IntrospectionException(msg);
363                }
364                else {
365                  setMethod = current;
366                  propertyType = current.getParameterTypes()[0];
367                }
368              }
369            }
370            if (setMethod == null) {
371              throw new IntrospectionException("Cannot find get or set methods.");
372            }
373          }
374          else {
375            throw new IntrospectionException("Cannot find get or set methods.");
376          }
377        }
378        catch (SecurityException E) {
379          String msg = "SecurityException thrown on attempt to access methods.";
380          throw new IntrospectionException(msg);
381        }
382      }
383  }  }

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8

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