KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > beanutils > PropertyUtilsBean


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.beanutils;
18
19
20 import java.beans.BeanInfo JavaDoc;
21 import java.beans.IndexedPropertyDescriptor JavaDoc;
22 import java.beans.IntrospectionException JavaDoc;
23 import java.beans.Introspector JavaDoc;
24 import java.beans.PropertyDescriptor JavaDoc;
25 import java.lang.reflect.Array JavaDoc;
26 import java.lang.reflect.InvocationTargetException JavaDoc;
27 import java.lang.reflect.Method JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32
33 import org.apache.commons.collections.FastHashMap;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37
38 /**
39  * Utility methods for using Java Reflection APIs to facilitate generic
40  * property getter and setter operations on Java objects. Much of this
41  * code was originally included in <code>BeanUtils</code>, but has been
42  * separated because of the volume of code involved.
43  * <p>
44  * In general, the objects that are examined and modified using these
45  * methods are expected to conform to the property getter and setter method
46  * naming conventions described in the JavaBeans Specification (Version 1.0.1).
47  * No data type conversions are performed, and there are no usage of any
48  * <code>PropertyEditor</code> classes that have been registered, although
49  * a convenient way to access the registered classes themselves is included.
50  * <p>
51  * For the purposes of this class, five formats for referencing a particular
52  * property value of a bean are defined, with the layout of an identifying
53  * String in parentheses:
54  * <ul>
55  * <li><strong>Simple (<code>name</code>)</strong> - The specified
56  * <code>name</code> identifies an individual property of a particular
57  * JavaBean. The name of the actual getter or setter method to be used
58  * is determined using standard JavaBeans instrospection, so that (unless
59  * overridden by a <code>BeanInfo</code> class, a property named "xyz"
60  * will have a getter method named <code>getXyz()</code> or (for boolean
61  * properties only) <code>isXyz()</code>, and a setter method named
62  * <code>setXyz()</code>.</li>
63  * <li><strong>Nested (<code>name1.name2.name3</code>)</strong> The first
64  * name element is used to select a property getter, as for simple
65  * references above. The object returned for this property is then
66  * consulted, using the same approach, for a property getter for a
67  * property named <code>name2</code>, and so on. The property value that
68  * is ultimately retrieved or modified is the one identified by the
69  * last name element.</li>
70  * <li><strong>Indexed (<code>name[index]</code>)</strong> - The underlying
71  * property value is assumed to be an array, or this JavaBean is assumed
72  * to have indexed property getter and setter methods. The appropriate
73  * (zero-relative) entry in the array is selected. <code>List</code>
74  * objects are now also supported for read/write. You simply need to define
75  * a getter that returns the <code>List</code></li>
76  * <li><strong>Mapped (<code>name(key)</code>)</strong> - The JavaBean
77  * is assumed to have an property getter and setter methods with an
78  * additional attribute of type <code>java.lang.String</code>.</li>
79  * <li><strong>Combined (<code>name1.name2[index].name3(key)</code>)</strong> -
80  * Combining mapped, nested, and indexed references is also
81  * supported.</li>
82  * </ul>
83  *
84  * @author Craig R. McClanahan
85  * @author Ralph Schaer
86  * @author Chris Audley
87  * @author Rey François
88  * @author Gregor Raıman
89  * @author Jan Sorensen
90  * @author Scott Sanders
91  * @version $Revision: 1.14.2.1 $ $Date: 2004/07/27 21:31:00 $
92  * @see PropertyUtils
93  * @since 1.7
94  */

95
96 public class PropertyUtilsBean {
97
98     // --------------------------------------------------------- Class Methods
99

100     protected static PropertyUtilsBean getInstance() {
101         return BeanUtilsBean.getInstance().getPropertyUtils();
102     }
103
104     // --------------------------------------------------------- Variables
105

106     /**
107      * The cache of PropertyDescriptor arrays for beans we have already
108      * introspected, keyed by the java.lang.Class of this object.
109      */

110     private FastHashMap descriptorsCache = null;
111     private FastHashMap mappedDescriptorsCache = null;
112     
113     /** Log instance */
114     private Log log = LogFactory.getLog(PropertyUtils.class);
115     
116     // ---------------------------------------------------------- Constructors
117

118     /** Base constructor */
119     public PropertyUtilsBean() {
120         descriptorsCache = new FastHashMap();
121         descriptorsCache.setFast(true);
122         mappedDescriptorsCache = new FastHashMap();
123         mappedDescriptorsCache.setFast(true);
124     }
125
126
127     // --------------------------------------------------------- Public Methods
128

129
130     /**
131      * Clear any cached property descriptors information for all classes
132      * loaded by any class loaders. This is useful in cases where class
133      * loaders are thrown away to implement class reloading.
134      */

135     public void clearDescriptors() {
136
137         descriptorsCache.clear();
138         mappedDescriptorsCache.clear();
139         Introspector.flushCaches();
140
141     }
142
143
144     /**
145      * <p>Copy property values from the "origin" bean to the "destination" bean
146      * for all cases where the property names are the same (even though the
147      * actual getter and setter methods might have been customized via
148      * <code>BeanInfo</code> classes). No conversions are performed on the
149      * actual property values -- it is assumed that the values retrieved from
150      * the origin bean are assignment-compatible with the types expected by
151      * the destination bean.</p>
152      *
153      * <p>If the origin "bean" is actually a <code>Map</code>, it is assumed
154      * to contain String-valued <strong>simple</strong> property names as the keys, pointing
155      * at the corresponding property values that will be set in the destination
156      * bean.<strong>Note</strong> that this method is intended to perform
157      * a "shallow copy" of the properties and so complex properties
158      * (for example, nested ones) will not be copied.</p>
159      *
160      * @param dest Destination bean whose properties are modified
161      * @param orig Origin bean whose properties are retrieved
162      *
163      * @exception IllegalAccessException if the caller does not have
164      * access to the property accessor method
165      * @exception IllegalArgumentException if the <code>dest</code> or
166      * <code>orig</code> argument is null
167      * @exception InvocationTargetException if the property accessor method
168      * throws an exception
169      * @exception NoSuchMethodException if an accessor method for this
170      * propety cannot be found
171      */

172     public void copyProperties(Object JavaDoc dest, Object JavaDoc orig)
173             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
174             NoSuchMethodException JavaDoc {
175
176         if (dest == null) {
177             throw new IllegalArgumentException JavaDoc
178                     ("No destination bean specified");
179         }
180         if (orig == null) {
181             throw new IllegalArgumentException JavaDoc("No origin bean specified");
182         }
183
184         if (orig instanceof DynaBean) {
185             DynaProperty origDescriptors[] =
186                 ((DynaBean) orig).getDynaClass().getDynaProperties();
187             for (int i = 0; i < origDescriptors.length; i++) {
188                 String JavaDoc name = origDescriptors[i].getName();
189                 if (dest instanceof DynaBean) {
190                     if (isWriteable(dest, name)) {
191                         Object JavaDoc value = ((DynaBean) orig).get(name);
192                         ((DynaBean) dest).set(name, value);
193                     }
194                 } else /* if (dest is a standard JavaBean) */ {
195                     if (isWriteable(dest, name)) {
196                         Object JavaDoc value = ((DynaBean) orig).get(name);
197                         setSimpleProperty(dest, name, value);
198                     }
199                 }
200             }
201         } else if (orig instanceof Map JavaDoc) {
202             Iterator JavaDoc names = ((Map JavaDoc) orig).keySet().iterator();
203             while (names.hasNext()) {
204                 String JavaDoc name = (String JavaDoc) names.next();
205                 if (dest instanceof DynaBean) {
206                     if (isWriteable(dest, name)) {
207                         Object JavaDoc value = ((Map JavaDoc) orig).get(name);
208                         ((DynaBean) dest).set(name, value);
209                     }
210                 } else /* if (dest is a standard JavaBean) */ {
211                     if (isWriteable(dest, name)) {
212                         Object JavaDoc value = ((Map JavaDoc) orig).get(name);
213                         setSimpleProperty(dest, name, value);
214                     }
215                 }
216             }
217         } else /* if (orig is a standard JavaBean) */ {
218             PropertyDescriptor JavaDoc origDescriptors[] =
219                 getPropertyDescriptors(orig);
220             for (int i = 0; i < origDescriptors.length; i++) {
221                 String JavaDoc name = origDescriptors[i].getName();
222                 if (isReadable(orig, name)) {
223                     if (dest instanceof DynaBean) {
224                         if (isWriteable(dest, name)) {
225                             Object JavaDoc value = getSimpleProperty(orig, name);
226                             ((DynaBean) dest).set(name, value);
227                         }
228                     } else /* if (dest is a standard JavaBean) */ {
229                         if (isWriteable(dest, name)) {
230                             Object JavaDoc value = getSimpleProperty(orig, name);
231                             setSimpleProperty(dest, name, value);
232                         }
233                     }
234                 }
235             }
236         }
237
238     }
239
240
241     /**
242      * <p>Return the entire set of properties for which the specified bean
243      * provides a read method. This map contains the unconverted property
244      * values for all properties for which a read method is provided
245      * (i.e. where the <code>getReadMethod()</code> returns non-null).</p>
246      *
247      * <p><strong>FIXME</strong> - Does not account for mapped properties.</p>
248      *
249      * @param bean Bean whose properties are to be extracted
250      *
251      * @exception IllegalAccessException if the caller does not have
252      * access to the property accessor method
253      * @exception IllegalArgumentException if <code>bean</code> is null
254      * @exception InvocationTargetException if the property accessor method
255      * throws an exception
256      * @exception NoSuchMethodException if an accessor method for this
257      * propety cannot be found
258      */

259     public Map JavaDoc describe(Object JavaDoc bean)
260             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
261             NoSuchMethodException JavaDoc {
262
263         if (bean == null) {
264             throw new IllegalArgumentException JavaDoc("No bean specified");
265         }
266         Map JavaDoc description = new HashMap JavaDoc();
267         if (bean instanceof DynaBean) {
268             DynaProperty descriptors[] =
269                 ((DynaBean) bean).getDynaClass().getDynaProperties();
270             for (int i = 0; i < descriptors.length; i++) {
271                 String JavaDoc name = descriptors[i].getName();
272                 description.put(name, getProperty(bean, name));
273             }
274         } else {
275             PropertyDescriptor JavaDoc descriptors[] =
276                 getPropertyDescriptors(bean);
277             for (int i = 0; i < descriptors.length; i++) {
278                 String JavaDoc name = descriptors[i].getName();
279                 if (descriptors[i].getReadMethod() != null)
280                     description.put(name, getProperty(bean, name));
281             }
282         }
283         return (description);
284
285     }
286
287
288     /**
289      * Return the value of the specified indexed property of the specified
290      * bean, with no type conversions. The zero-relative index of the
291      * required value must be included (in square brackets) as a suffix to
292      * the property name, or <code>IllegalArgumentException</code> will be
293      * thrown. In addition to supporting the JavaBeans specification, this
294      * method has been extended to support <code>List</code> objects as well.
295      *
296      * @param bean Bean whose property is to be extracted
297      * @param name <code>propertyname[index]</code> of the property value
298      * to be extracted
299      *
300      * @exception ArrayIndexOutOfBoundsException if the specified index
301      * is outside the valid range for the underlying array
302      * @exception IllegalAccessException if the caller does not have
303      * access to the property accessor method
304      * @exception IllegalArgumentException if <code>bean</code> or
305      * <code>name</code> is null
306      * @exception InvocationTargetException if the property accessor method
307      * throws an exception
308      * @exception NoSuchMethodException if an accessor method for this
309      * propety cannot be found
310      */

311     public Object JavaDoc getIndexedProperty(Object JavaDoc bean, String JavaDoc name)
312             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
313             NoSuchMethodException JavaDoc {
314
315         if (bean == null) {
316             throw new IllegalArgumentException JavaDoc("No bean specified");
317         }
318         if (name == null) {
319             throw new IllegalArgumentException JavaDoc("No name specified");
320         }
321
322         // Identify the index of the requested individual property
323
int delim = name.indexOf(PropertyUtils.INDEXED_DELIM);
324         int delim2 = name.indexOf(PropertyUtils.INDEXED_DELIM2);
325         if ((delim < 0) || (delim2 <= delim)) {
326             throw new IllegalArgumentException JavaDoc("Invalid indexed property '" +
327                     name + "'");
328         }
329         int index = -1;
330         try {
331             String JavaDoc subscript = name.substring(delim + 1, delim2);
332             index = Integer.parseInt(subscript);
333         } catch (NumberFormatException JavaDoc e) {
334             throw new IllegalArgumentException JavaDoc("Invalid indexed property '" +
335                     name + "'");
336         }
337         name = name.substring(0, delim);
338
339         // Request the specified indexed property value
340
return (getIndexedProperty(bean, name, index));
341
342     }
343
344
345     /**
346      * Return the value of the specified indexed property of the specified
347      * bean, with no type conversions. In addition to supporting the JavaBeans
348      * specification, this method has been extended to support
349      * <code>List</code> objects as well.
350      *
351      * @param bean Bean whose property is to be extracted
352      * @param name Simple property name of the property value to be extracted
353      * @param index Index of the property value to be extracted
354      *
355      * @exception ArrayIndexOutOfBoundsException if the specified index
356      * is outside the valid range for the underlying array
357      * @exception IllegalAccessException if the caller does not have
358      * access to the property accessor method
359      * @exception IllegalArgumentException if <code>bean</code> or
360      * <code>name</code> is null
361      * @exception InvocationTargetException if the property accessor method
362      * throws an exception
363      * @exception NoSuchMethodException if an accessor method for this
364      * propety cannot be found
365      */

366     public Object JavaDoc getIndexedProperty(Object JavaDoc bean,
367                                             String JavaDoc name, int index)
368             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
369             NoSuchMethodException JavaDoc {
370
371         if (bean == null) {
372             throw new IllegalArgumentException JavaDoc("No bean specified");
373         }
374         if (name == null) {
375             throw new IllegalArgumentException JavaDoc("No name specified");
376         }
377
378         // Handle DynaBean instances specially
379
if (bean instanceof DynaBean) {
380             DynaProperty descriptor =
381                     ((DynaBean) bean).getDynaClass().getDynaProperty(name);
382             if (descriptor == null) {
383                 throw new NoSuchMethodException JavaDoc("Unknown property '" +
384                         name + "'");
385             }
386             return (((DynaBean) bean).get(name, index));
387         }
388
389         // Retrieve the property descriptor for the specified property
390
PropertyDescriptor JavaDoc descriptor =
391                 getPropertyDescriptor(bean, name);
392         if (descriptor == null) {
393             throw new NoSuchMethodException JavaDoc("Unknown property '" +
394                     name + "'");
395         }
396
397         // Call the indexed getter method if there is one
398
if (descriptor instanceof IndexedPropertyDescriptor JavaDoc) {
399             Method JavaDoc readMethod = ((IndexedPropertyDescriptor JavaDoc) descriptor).
400                     getIndexedReadMethod();
401             if (readMethod != null) {
402                 Object JavaDoc subscript[] = new Object JavaDoc[1];
403                 subscript[0] = new Integer JavaDoc(index);
404                 try {
405                     return (invokeMethod(readMethod,bean, subscript));
406                 } catch (InvocationTargetException JavaDoc e) {
407                     if (e.getTargetException() instanceof
408                             ArrayIndexOutOfBoundsException JavaDoc) {
409                         throw (ArrayIndexOutOfBoundsException JavaDoc)
410                                 e.getTargetException();
411                     } else {
412                         throw e;
413                     }
414                 }
415             }
416         }
417
418         // Otherwise, the underlying property must be an array
419
Method JavaDoc readMethod = getReadMethod(descriptor);
420         if (readMethod == null) {
421             throw new NoSuchMethodException JavaDoc("Property '" + name +
422                     "' has no getter method");
423         }
424
425         // Call the property getter and return the value
426
Object JavaDoc value = invokeMethod(readMethod, bean, new Object JavaDoc[0]);
427         if (!value.getClass().isArray()) {
428             if (!(value instanceof java.util.List JavaDoc)) {
429                 throw new IllegalArgumentException JavaDoc("Property '" + name
430                         + "' is not indexed");
431             } else {
432                 //get the List's value
433
return ((java.util.List JavaDoc) value).get(index);
434             }
435         } else {
436             //get the array's value
437
return (Array.get(value, index));
438         }
439
440     }
441
442
443     /**
444      * Return the value of the specified mapped property of the
445      * specified bean, with no type conversions. The key of the
446      * required value must be included (in brackets) as a suffix to
447      * the property name, or <code>IllegalArgumentException</code> will be
448      * thrown.
449      *
450      * @param bean Bean whose property is to be extracted
451      * @param name <code>propertyname(key)</code> of the property value
452      * to be extracted
453      *
454      * @exception IllegalAccessException if the caller does not have
455      * access to the property accessor method
456      * @exception InvocationTargetException if the property accessor method
457      * throws an exception
458      * @exception NoSuchMethodException if an accessor method for this
459      * propety cannot be found
460      */

461     public Object JavaDoc getMappedProperty(Object JavaDoc bean, String JavaDoc name)
462             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
463             NoSuchMethodException JavaDoc {
464
465         if (bean == null) {
466             throw new IllegalArgumentException JavaDoc("No bean specified");
467         }
468         if (name == null) {
469             throw new IllegalArgumentException JavaDoc("No name specified");
470         }
471
472         // Identify the index of the requested individual property
473
int delim = name.indexOf(PropertyUtils.MAPPED_DELIM);
474         int delim2 = name.indexOf(PropertyUtils.MAPPED_DELIM2);
475         if ((delim < 0) || (delim2 <= delim)) {
476             throw new IllegalArgumentException JavaDoc
477                     ("Invalid mapped property '" + name + "'");
478         }
479
480         // Isolate the name and the key
481
String JavaDoc key = name.substring(delim + 1, delim2);
482         name = name.substring(0, delim);
483
484         // Request the specified indexed property value
485
return (getMappedProperty(bean, name, key));
486
487     }
488
489
490     /**
491      * Return the value of the specified mapped property of the specified
492      * bean, with no type conversions.
493      *
494      * @param bean Bean whose property is to be extracted
495      * @param name Mapped property name of the property value to be extracted
496      * @param key Key of the property value to be extracted
497      *
498      * @exception IllegalAccessException if the caller does not have
499      * access to the property accessor method
500      * @exception InvocationTargetException if the property accessor method
501      * throws an exception
502      * @exception NoSuchMethodException if an accessor method for this
503      * propety cannot be found
504      */

505     public Object JavaDoc getMappedProperty(Object JavaDoc bean,
506                                            String JavaDoc name, String JavaDoc key)
507             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
508             NoSuchMethodException JavaDoc {
509
510         if (bean == null) {
511             throw new IllegalArgumentException JavaDoc("No bean specified");
512         }
513         if (name == null) {
514             throw new IllegalArgumentException JavaDoc("No name specified");
515         }
516         if (key == null) {
517             throw new IllegalArgumentException JavaDoc("No key specified");
518         }
519
520         // Handle DynaBean instances specially
521
if (bean instanceof DynaBean) {
522             DynaProperty descriptor =
523                     ((DynaBean) bean).getDynaClass().getDynaProperty(name);
524             if (descriptor == null) {
525                 throw new NoSuchMethodException JavaDoc("Unknown property '" +
526                         name + "'");
527             }
528             return (((DynaBean) bean).get(name, key));
529         }
530
531         Object JavaDoc result = null;
532
533         // Retrieve the property descriptor for the specified property
534
PropertyDescriptor JavaDoc descriptor = getPropertyDescriptor(bean, name);
535         if (descriptor == null) {
536             throw new NoSuchMethodException JavaDoc("Unknown property '" +
537                     name + "'");
538         }
539
540         if (descriptor instanceof MappedPropertyDescriptor) {
541             // Call the keyed getter method if there is one
542
Method JavaDoc readMethod = ((MappedPropertyDescriptor) descriptor).
543                     getMappedReadMethod();
544             if (readMethod != null) {
545                 Object JavaDoc keyArray[] = new Object JavaDoc[1];
546                 keyArray[0] = key;
547                 result = invokeMethod(readMethod, bean, keyArray);
548             } else {
549                 throw new NoSuchMethodException JavaDoc("Property '" + name +
550                         "' has no mapped getter method");
551             }
552         } else {
553           /* means that the result has to be retrieved from a map */
554           Method JavaDoc readMethod = descriptor.getReadMethod();
555           if (readMethod != null) {
556             Object JavaDoc invokeResult = invokeMethod(readMethod, bean, new Object JavaDoc[0]);
557             /* test and fetch from the map */
558             if (invokeResult instanceof java.util.Map JavaDoc) {
559               result = ((java.util.Map JavaDoc)invokeResult).get(key);
560             }
561           } else {
562             throw new NoSuchMethodException JavaDoc("Property '" + name +
563                     "' has no mapped getter method");
564           }
565         }
566         return result;
567
568     }
569
570
571     /**
572      * <p>Return the mapped property descriptors for this bean class.</p>
573      *
574      * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
575      *
576      * @param beanClass Bean class to be introspected
577      * @deprecated This method should not be exposed
578      */

579     public FastHashMap getMappedPropertyDescriptors(Class JavaDoc beanClass) {
580
581         if (beanClass == null) {
582             return null;
583         }
584
585         // Look up any cached descriptors for this bean class
586
return (FastHashMap) mappedDescriptorsCache.get(beanClass);
587
588     }
589
590
591     /**
592      * <p>Return the mapped property descriptors for this bean.</p>
593      *
594      * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
595      *
596      * @param bean Bean to be introspected
597      * @deprecated This method should not be exposed
598      */

599     public FastHashMap getMappedPropertyDescriptors(Object JavaDoc bean) {
600
601         if (bean == null) {
602             return null;
603         }
604         return (getMappedPropertyDescriptors(bean.getClass()));
605
606     }
607
608
609     /**
610      * Return the value of the (possibly nested) property of the specified
611      * name, for the specified bean, with no type conversions.
612      *
613      * @param bean Bean whose property is to be extracted
614      * @param name Possibly nested name of the property to be extracted
615      *
616      * @exception IllegalAccessException if the caller does not have
617      * access to the property accessor method
618      * @exception IllegalArgumentException if <code>bean</code> or
619      * <code>name</code> is null
620      * @exception NestedNullException if a nested reference to a
621      * property returns null
622      * @exception InvocationTargetException
623      * if the property accessor method throws an exception
624      * @exception NoSuchMethodException if an accessor method for this
625      * propety cannot be found
626      */

627     public Object JavaDoc getNestedProperty(Object JavaDoc bean, String JavaDoc name)
628             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
629             NoSuchMethodException JavaDoc {
630
631         if (bean == null) {
632             throw new IllegalArgumentException JavaDoc("No bean specified");
633         }
634         if (name == null) {
635             throw new IllegalArgumentException JavaDoc("No name specified");
636         }
637
638         int indexOfINDEXED_DELIM = -1;
639         int indexOfMAPPED_DELIM = -1;
640         int indexOfMAPPED_DELIM2 = -1;
641         int indexOfNESTED_DELIM = -1;
642         while (true) {
643             indexOfNESTED_DELIM = name.indexOf(PropertyUtils.NESTED_DELIM);
644             indexOfMAPPED_DELIM = name.indexOf(PropertyUtils.MAPPED_DELIM);
645             indexOfMAPPED_DELIM2 = name.indexOf(PropertyUtils.MAPPED_DELIM2);
646             if (indexOfMAPPED_DELIM2 >= 0 && indexOfMAPPED_DELIM >=0 &&
647                 (indexOfNESTED_DELIM < 0 || indexOfNESTED_DELIM > indexOfMAPPED_DELIM)) {
648                 indexOfNESTED_DELIM =
649                     name.indexOf(PropertyUtils.NESTED_DELIM, indexOfMAPPED_DELIM2);
650             } else {
651                 indexOfNESTED_DELIM = name.indexOf(PropertyUtils.NESTED_DELIM);
652             }
653             if (indexOfNESTED_DELIM < 0) {
654                 break;
655             }
656             String JavaDoc next = name.substring(0, indexOfNESTED_DELIM);
657             indexOfINDEXED_DELIM = next.indexOf(PropertyUtils.INDEXED_DELIM);
658             indexOfMAPPED_DELIM = next.indexOf(PropertyUtils.MAPPED_DELIM);
659             if (bean instanceof Map JavaDoc) {
660                 bean = ((Map JavaDoc) bean).get(next);
661             } else if (indexOfMAPPED_DELIM >= 0) {
662                 bean = getMappedProperty(bean, next);
663             } else if (indexOfINDEXED_DELIM >= 0) {
664                 bean = getIndexedProperty(bean, next);
665             } else {
666                 bean = getSimpleProperty(bean, next);
667             }
668             if (bean == null) {
669                 throw new NestedNullException
670                         ("Null property value for '" +
671                         name.substring(0, indexOfNESTED_DELIM) + "'");
672             }
673             name = name.substring(indexOfNESTED_DELIM + 1);
674         }
675
676         indexOfINDEXED_DELIM = name.indexOf(PropertyUtils.INDEXED_DELIM);
677         indexOfMAPPED_DELIM = name.indexOf(PropertyUtils.MAPPED_DELIM);
678
679         if (bean instanceof Map JavaDoc) {
680             bean = ((Map JavaDoc) bean).get(name);
681         } else if (indexOfMAPPED_DELIM >= 0) {
682             bean = getMappedProperty(bean, name);
683         } else if (indexOfINDEXED_DELIM >= 0) {
684             bean = getIndexedProperty(bean, name);
685         } else {
686             bean = getSimpleProperty(bean, name);
687         }
688         return bean;
689
690     }
691
692
693     /**
694      * Return the value of the specified property of the specified bean,
695      * no matter which property reference format is used, with no
696      * type conversions.
697      *
698      * @param bean Bean whose property is to be extracted
699      * @param name Possibly indexed and/or nested name of the property
700      * to be extracted
701      *
702      * @exception IllegalAccessException if the caller does not have
703      * access to the property accessor method
704      * @exception IllegalArgumentException if <code>bean</code> or
705      * <code>name</code> is null
706      * @exception InvocationTargetException if the property accessor method
707      * throws an exception
708      * @exception NoSuchMethodException if an accessor method for this
709      * propety cannot be found
710      */

711     public Object JavaDoc getProperty(Object JavaDoc bean, String JavaDoc name)
712             throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
713             NoSuchMethodException JavaDoc {
714
715         return (getNestedProperty(bean, name));
716
717     }
718
719
720     /**
721      * <p>Retrieve the property descriptor for the specified property of the
722      * specified bean, or return <code>null</code> if there is no such
723      * descriptor. This method resolves indexed and nested property
724      * references in the same manner as other methods in this class, except
725      * that if the last (or only) name element is indexed, the descriptor
726      * for the last resolved property itself is returned.</p>
727      *
728      * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
729      *
730      * @param bean Bean for which a property descriptor is requested
731      * @param name Possibly indexed and/or nested name of the property for
732      * which a property descriptor is requested
733      *
734      * @exception IllegalAccessException if the caller does not have
735      * access to the property accessor method
736      * @exception IllegalArgumentException if <code>bean</code> or
737      * <code>name</code> is null
738      * @exception IllegalArgumentException if a nested reference to a
739      * property returns null
740