KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > inversoft > beans > NestedBeanProperty


1 /*
2  * Copyright (c) 2003, Inversoft
3  *
4  * This software is distribuable under the GNU Lesser General Public License.
5  * For more information visit gnu.org.
6  */

7 package com.inversoft.beans;
8
9
10 import java.util.List JavaDoc;
11
12 import com.inversoft.util.typeconverter.TypeConversionException;
13
14
15 /**
16  * <p>
17  * This class is used to store information about and handle
18  * getting and setting of both nested and local properties.
19  * </p>
20  *
21  * <p>
22  * A nested property is normally retrieved with a statement
23  * like:
24  * </p>
25  *
26  * <p>
27  * <code>getProperty1().getProperty2().getProperty3()...</code>
28  * </p>
29  *
30  * <p>
31  * and set like:
32  * </p>
33  *
34  * <p>
35  * <code>getProperty1().getProperty2()...setPropertyN(value)</code>.
36  * </p>
37  *
38  * <p>
39  * This class allows these type of properties to be handled
40  * using simple dot notation and JavaBean property names. So
41  * the above example would be notated like:
42  * </p>
43  *
44  * <p>
45  * <code>property1.property2...propertyN</code>
46  * </p>
47  *
48  * <p>
49  * This notation allows this class to be setup so that nested
50  * properties can be retrieved and set.
51  * </p>
52  *
53  * <p>
54  * It also allows nested properties to be auto generated.
55  * What this means is that if, for the example above,
56  * getProperty1() returns null, then a new instance of the
57  * return type for getProperty1 is created and set using
58  * setProperty1(newInstance).
59  * </p>
60  *
61  * <p>
62  * Local properties are just plain old JavaBean properties
63  * which are normally described by java.beans.PropertyDescriptor
64  * and have the form propertyName, which would equate to
65  * getPropertyName() and setPropertyName() (or isPropertyName
66  * for boolean values). This class can be used to access these
67  * types of properties in addition to the nested properties.
68  * </p>
69  *
70  * <p>
71  * The way that null children are handled can be changed for
72  * this class. Null children are described as nested properties
73  * that need to be auto generated using the method described
74  * above. This is done using the strict member of the class
75  * via a constructor or the strict property methods. If this
76  * class describes a nested property and while traversing the
77  * nesting a null value is encountered, the value of strict
78  * determines is an exception is thrown or the property is
79  * auto generated. For example, if the property is foo.bar.value
80  * and a call to getFoo() returns a null value, then one of
81  * the following outcomes will occur:
82  * </p>
83  *
84  * <p>
85  * <ul>
86  * <li>If strict is false, and the {@link #getPropertyValue(Object)
87  * getPropertyValue()} method was called, then null is returned.
88  * </li>
89  *
90  * <li>If strict is false and the setPropertyValue method was
91  * called, then a new instance of the return type for getFoo
92  * is created using the default constructor and set using
93  * the setFoo() method.
94  * </li>
95  *
96  * <li>If strict is true and either getPropertyValue or
97  * setPropertyValue was called, then an exception is thrown.
98  * </li>
99  * </ul>
100  * </p>
101  *
102  * <p>
103  * This class also handles a mixed set of indexed and normal
104  * properties in the nesting. For example, you could access
105  * a property such as:
106  * </p>
107  *
108  * <p>
109  * <code>getIndexed(1).getProperty2().getValue()</code><p>
110  * </p>
111  *
112  * <p>
113  * using this class. The constructor takes the name of the
114  * property without distinguishing between indexed and normal
115  * properties. So, for the example above, the constructor
116  * would take a property String like:
117  * <tt>indexed.property2.value</tt>. Then when the property
118  * value is being retrieved or changed, the indices values are
119  * passed in with either an array of ints or a List of
120  * Integer wrappers.
121  * </p>
122  *
123  * <p>
124  * This class also supports the use of identified indexing
125  * which means that the property name string contains the
126  * indices values. For example:
127  * <code>indexed[1].property2.value</code>
128  * is a valid property String. In this case, the indexed
129  * property will be retrieved with an indices of 1.
130  * </p>
131  *
132  * @author Brian Pontarelli
133  */

134 public class NestedBeanProperty extends BaseBeanProperty {
135
136     JavaBean javaBean;
137     List JavaDoc info;
138     boolean strict;
139     BeanProperty root;
140     JavaBeanTools.PropertyInfo rootPi;
141
142     /**
143      * Default constructor that can be used by sub-classes that want to delay the
144      * initialization of the propertyName and beanClass or that do not use these
145      * members. This constructor also calls the default constructor from the
146      * BaseBeanProperty super-class. This means that using this constructor will
147      * not make a template method call to {@link #initialize() #initialize()}.
148      */

149     protected NestedBeanProperty() {
150         super();
151         strict = false;
152     }
153
154     /**
155      * Constructs a new NestedBeanProperty that can be used to describe nested or
156      * local properties, depending on the value of the property string (see
157      * the class comment for more information). It also uses the class given
158      * to construct the method list.
159      *
160      * @param propertyName The name of the local or nested property
161      * @param beanClass The class to build the property for
162      * @throws BeanException If anything went wrong during the parsing of the
163      * property string or building of the property list
164      */

165     public NestedBeanProperty(String JavaDoc propertyName, Class JavaDoc beanClass)
166     throws BeanException {
167         this(propertyName, beanClass, false); // Super constructor calls initialize
168
}
169
170     /**
171      * Constructs a new NestedBeanProperty that can be used to describe nested or
172      * local properties, depending on the value of the property string (see
173      * the class comment for more information). It also uses the given fully
174      * qualified name of the bean class and the propertyName to construct the
175      * method list.
176      *
177      * @param propertyName The name of the local or nested property
178      * @param beanClass The fully qualified name of the bean class to build the
179      * property for
180      * @throws BeanException If anything went wrong during the parsing of the
181      * property string or building of the property list
182      */

183     public NestedBeanProperty(String JavaDoc propertyName, String JavaDoc beanClass)
184     throws BeanException {
185         this(propertyName, beanClass, false); // Super constructor calls initialize
186
}
187
188     /**
189      * Constructs a new NestedBeanProperty that can be used to describe nested or
190      * local properties, depending on the value of the property string (see
191      * the class comment for more information). It also uses the class given
192      * to construct the method list.
193      *
194      * @param propertyName The name of the property or deep property String
195      * @param beanClass The class to build the property for
196      * @param strict Determines how this class handles cases when setting and
197      * retrieving property values where nested properties need to be
198      * auto generated because they are null
199      * @throws BeanException If anything went wrong during the parsing of
200      * the property string or building of the property list
201      */

202     public NestedBeanProperty(String JavaDoc propertyName, Class JavaDoc beanClass, boolean strict)
203     throws BeanException {
204         super(propertyName, beanClass); // Super constructor calls initialize
205
this.strict = strict;
206     }
207
208     /**
209      * Constructs a new NestedBeanProperty that can be used to describe nested or
210      * local properties, depending on the value of the property string (see
211      * the class comment for more information). It also uses the given fully
212      * qualified name of the bean class and the propertyName to construct the
213      * method list.
214      *
215      * @param propertyName The name of the property or deep property String
216      * @param beanClass The fully qualified name of the bean class to build the
217      * property for
218      * @param strict Determines how this class handles cases when setting and
219      * retrieving property values where nested properties need to be
220      * auto generated because they are null
221      * @throws BeanException If anything went wrong during the parsing of
222      * the property string or building of the property list
223      */

224     public NestedBeanProperty(String JavaDoc propertyName, String JavaDoc beanClass, boolean strict)
225     throws BeanException {
226         super(propertyName, beanClass); // Super constructor calls initialize
227
this.strict = strict;
228     }
229
230     /**
231      * Initializes all the members of this class by parsing out the propertyName String
232      * and creating the necessary BeanProperty class and everything else that might
233      * be needed.
234      *
235      * @throws BeanException If there were any problems initializing this class
236      */

237     protected void initialize() throws BeanException {
238         javaBean = new JavaBean(beanClass);
239         JavaBeanTools.NameInfo ni = JavaBeanTools.splitNameFront(propertyName);
240         JavaBeanTools.PropertyInfo pi =
241             JavaBeanTools.retrievePropertyInfo(ni.localPropertyName);
242
243         root = javaBean.getBeanProperty(pi.propertyName);
244     }
245
246     /**
247      * Gets the strictness property of this instance
248      */

249     public boolean isStrict() {
250         return strict;
251     }
252
253     /**
254      * Sets the strictness property for this instance
255      */

256     public void setStrict(boolean value) {
257         strict = value;
258     }
259
260     /**
261      * Returns the base property of nested properties or the property of local
262      * properties. For example, if the property name is property1.property2, this
263      * method would return an instance of BeanProperty for property1.
264      *
265      * @return The base BeanProperty
266      */

267     public BeanProperty getRootProperty() {
268         return root;
269     }
270
271     /**
272      * OVerrides the getPropertyType in BaseBeanProperty. This is a brute force
273      * retrieval attempt using the declared properties. This may fail and return
274      * null.
275      */

276     public Class JavaDoc getPropertyType() {
277         Class JavaDoc type = null;
278         try {
279             BeanProperty bp = javaBean.getBeanProperty(propertyName);
280             if (bp != null) {
281                 type = bp.getPropertyType();
282             }
283         } catch (BeanException be) {
284             // Smother and return null as the method doc says
285
}
286
287         return type;
288     }
289
290     /**
291      * Returns the value of the local or nested property described by this
292      * instance.
293      *
294      * @param bean The bean to retrieve the property on
295      * @return The value of the property
296      * @throws BeanException If there was an error getting the JavaBean property or
297      * the getter/is method threw a checked Exception or if strict is true
298      * and a null non-leaf property was encountered
299      */

300     public Object JavaDoc getPropertyValue(final Object JavaDoc bean) throws BeanException {
301         return getPropertyValue(bean, (List JavaDoc) null);
302     }
303
304     /**
305      * Returns the value of the local or nested property described by this
306      * instance.
307      *
308      * @param bean The bean to retrieve the property on
309      * @param indices (Optional) The list of indices used when retrieving the
310      * property. This can be null if there are no indexed properties in
311      * the nesting.
312      * @return The value of the property
313      * @throws BeanException If there was an error getting the JavaBean property or
314      * the getter/is method threw a checked Exception or if strict is true
315      * and a null non-leaf property was encountered
316      */

317     public Object JavaDoc getPropertyValue(final Object JavaDoc bean, final List JavaDoc indices)
318     throws BeanException {
319
320         Object JavaDoc value = javaBean.getPropertyValue(propertyName, bean, indices, strict);
321         if (hasPropertyListeners()) {
322             firePropertyEvent(GET, value, value, bean, indices);
323         }
324
325         return value;
326     }
327
328     /**
329      * Returns the value of the local or nested property described by this
330      * instance.
331      *
332      * @param bean The bean to retrieve the property on
333      * @param indices (Optional) The array of indices used when retrieving the
334      * property. This can be null if there are no indexed properties in
335      * the nesting
336      * @return The value of the property
337      * @throws BeanException If there was an error getting the JavaBean property or
338      * the getter/is method threw a checked Exception or if strict is true
339      * and a null non-leaf property was encountered
340      */

341     public Object JavaDoc getPropertyValue(final Object JavaDoc bean, final int [][] indices)
342     throws BeanException {
343         List JavaDoc list = javaBean.convertArray(indices);
344         return getPropertyValue(bean, list);
345     }
346
347     /**
348      * Sets the local or nested property value described by this instance. This method
349      * will optionally try to convert the value parameter to the correct type for the
350      * property.
351      *
352      * @param bean The bean instance to set the property on
353      * @param value The value to set on the bean
354      * @param convert Determines whether or not the value should be converted
355      * to the correct parameter type for the property set method
356      * @throws BeanException If there was an error setting the JavaBean property or
357      * the setter method threw a checked Exception or if strict is true
358      * an a null non-leaf property was encountered
359      * @throws TypeConversionException If there was an error attempting to auto
360      * convert the value being set
361      */

362     public void setPropertyValue(final Object JavaDoc bean, Object JavaDoc value,
363             final boolean convert)
364     throws BeanException, TypeConversionException {
365         setPropertyValue(bean, (List JavaDoc) null, value, convert);
366     }
367
368     /**
369      * Sets the local or nested property value described by this instance. This method
370      * will optionally try to convert the value parameter to the correct type for the
371      * property.
372      *
373      * @param bean The bean instance to set the property on
374      * @param indices (Optional) The List indices used when setting the property.
375      * This can be null if there are no indexed properties in the nesting
376      * @param value The value to set on the bean
377      * @param convert Determines whether or not the value should be converted
378      * to the correct parameter type for the property set method
379      * @throws BeanException If there was an error setting the JavaBean property or
380      * the setter method threw a checked Exception or if strict is true
381      * an a null non-leaf property was encountered
382      * @throws TypeConversionException If there was an error attempting to auto
383      * convert the value being set
384      */

385     public void setPropertyValue(final Object JavaDoc bean, final List JavaDoc indices, Object JavaDoc value,
386             final boolean convert)
387     throws BeanException, TypeConversionException {
388
389         Object JavaDoc oldValue = null;
390         if (hasPropertyListeners()) {
391             oldValue = javaBean.getPropertyValue(propertyName, bean, indices, strict);
392         }
393
394         javaBean.setPropertyValue(propertyName, bean, indices, value, convert, strict);
395
396         if (hasPropertyListeners()) {
397             firePropertyEvent(SET, oldValue, value, bean, indices);
398         }
399     }
400
401     /**
402      * Sets the local or nested property value described by this instance. This method
403      * will optionally try to convert the value parameter to the correct type for the
404      * property.
405      *
406      * @param bean The bean instance to set the property on
407      * @param indices (Optional) The array of indices used when setting the property.
408      * This can be null if there are no indexed properties in the nesting
409      * @param value The value to set on the bean
410      * @param convert Determines whether or not the value should be converted
411      * to the correct parameter type for the property set method
412      * @throws BeanException If there was an error setting the JavaBean property or
413      * the setter method threw a checked Exception or if strict is true
414      * an a null non-leaf property was encountered
415      * @throws TypeConversionException If there was an error attempting to auto
416      * convert the value being set
417      */

418     public void setPropertyValue(final Object JavaDoc bean, final int[][] indices, Object JavaDoc value,
419             final boolean convert)
420     throws BeanException, TypeConversionException {
421         List JavaDoc list = javaBean.convertArray(indices);
422         setPropertyValue(bean, list, value, convert);
423     }
424 }
Popular Tags