View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.commons.beanutils;
20  
21  
22  import java.beans.IntrospectionException;
23  import java.beans.PropertyDescriptor;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  
34  import junit.framework.Test;
35  import junit.framework.TestCase;
36  import junit.framework.TestSuite;
37  
38  import org.apache.commons.beanutils.priv.PrivateBeanFactory;
39  import org.apache.commons.beanutils.priv.PrivateDirect;
40  import org.apache.commons.beanutils.priv.PublicSubBean;
41  
42  
43  /**
44   * <p>Test Case for the PropertyUtils class.  The majority of these tests use
45   * instances of the TestBean class, so be sure to update the tests if you
46   * change the characteristics of that class.</p>
47   *
48   * <p>So far, this test case has tests for the following methods of the
49   * <code>PropertyUtils</code> class:</p>
50   * <ul>
51   * <li>getIndexedProperty(Object,String)</li>
52   * <li>getIndexedProperty(Object,String,int)</li>
53   * <li>getMappedProperty(Object,String)</li>
54   * <li>getMappedProperty(Object,String,String</li>
55   * <li>getNestedProperty(Object,String)</li>
56   * <li>getPropertyDescriptor(Object,String)</li>
57   * <li>getPropertyDescriptors(Object)</li>
58   * <li>getPropertyType(Object,String)</li>
59   * <li>getSimpleProperty(Object,String)</li>
60   * <li>setIndexedProperty(Object,String,Object)</li>
61   * <li>setIndexedProperty(Object,String,String,Object)</li>
62   * <li>setMappedProperty(Object,String,Object)</li>
63   * <li>setMappedProperty(Object,String,String,Object)</li>
64   * <li>setNestedProperty(Object,String,Object)</li>
65   * <li>setSimpleProperty(Object,String,Object)</li>
66   * </ul>
67   *
68   * @version $Id$
69   */
70  
71  public class PropertyUtilsTestCase extends TestCase {
72  
73  
74      // ---------------------------------------------------- Instance Variables
75  
76  
77      /**
78       * The fully qualified class name of our private directly
79       * implemented interface.
80       */
81      private static final String PRIVATE_DIRECT_CLASS =
82              "org.apache.commons.beanutils.priv.PrivateDirect";
83  
84  
85      /**
86       * The fully qualified class name of our private indirectly
87       * implemented interface.
88       */
89      private static final String PRIVATE_INDIRECT_CLASS =
90              "org.apache.commons.beanutils.priv.PrivateIndirect";
91  
92  
93      /**
94       * The fully qualified class name of our test bean class.
95       */
96      private static final String TEST_BEAN_CLASS =
97              "org.apache.commons.beanutils.TestBean";
98  
99  
100     /**
101      * The basic test bean for each test.
102      */
103     protected TestBean bean = null;
104 
105 
106     /**
107      * The "package private subclass" test bean for each test.
108      */
109     protected TestBeanPackageSubclass beanPackageSubclass = null;
110 
111 
112     /**
113      * The test bean for private access tests.
114      */
115     protected PrivateDirect beanPrivate = null;
116 
117 
118     /**
119      * The test bean for private access tests of subclasses.
120      */
121     protected PrivateDirect beanPrivateSubclass = null;
122 
123 
124     /**
125      * The "public subclass" test bean for each test.
126      */
127     protected TestBeanPublicSubclass beanPublicSubclass = null;
128 
129 
130     /**
131      * The set of properties that should be described.
132      */
133     protected String describes[] =
134     { "booleanProperty",
135       "booleanSecond",
136       "doubleProperty",
137       "floatProperty",
138       "intArray",
139       //      "intIndexed",
140       "intProperty",
141       "listIndexed",
142       "longProperty",
143       //      "mappedObjects",
144       //      "mappedProperty",
145       //      "mappedIntProperty",
146       "nested",
147       "nullProperty",
148       //      "readOnlyProperty",
149       "shortProperty",
150       "stringArray",
151       //      "stringIndexed",
152       "stringProperty"
153     };
154 
155 
156     /**
157      * The set of property names we expect to have returned when calling
158      * <code>getPropertyDescriptors()</code>.  You should update this list
159      * when new properties are added to TestBean.
160      */
161     protected final static String[] properties = {
162         "booleanProperty",
163         "booleanSecond",
164         "doubleProperty",
165         "dupProperty",
166         "floatProperty",
167         "intArray",
168         "intIndexed",
169         "intProperty",
170         "listIndexed",
171         "longProperty",
172         "nested",
173         "nullProperty",
174         "readOnlyProperty",
175         "shortProperty",
176         "stringArray",
177         "stringIndexed",
178         "stringProperty",
179         "writeOnlyProperty",
180     };
181 
182 
183     // ---------------------------------------------------------- Constructors
184 
185 
186     /**
187      * Construct a new instance of this test case.
188      *
189      * @param name Name of the test case
190      */
191     public PropertyUtilsTestCase(final String name) {
192 
193         super(name);
194 
195     }
196 
197 
198     // -------------------------------------------------- Overall Test Methods
199 
200 
201     /**
202      * Set up instance variables required by this test case.
203      */
204     @Override
205     public void setUp() {
206 
207         bean = new TestBean();
208         beanPackageSubclass = new TestBeanPackageSubclass();
209         beanPrivate = PrivateBeanFactory.create();
210         beanPrivateSubclass = PrivateBeanFactory.createSubclass();
211         beanPublicSubclass = new TestBeanPublicSubclass();
212 
213         final DynaProperty[] properties = new DynaProperty[] {
214                 new DynaProperty("stringProperty", String.class),
215                 new DynaProperty("nestedBean", TestBean.class),
216                 new DynaProperty("nullDynaBean", DynaBean.class)
217                 };
218         final BasicDynaClass dynaClass = new BasicDynaClass("nestedDynaBean", BasicDynaBean.class, properties);
219         final BasicDynaBean nestedDynaBean = new BasicDynaBean(dynaClass);
220         nestedDynaBean.set("nestedBean", bean);
221         bean.setNestedDynaBean(nestedDynaBean);
222         PropertyUtils.clearDescriptors();
223     }
224 
225 
226     /**
227      * Return the tests included in this test suite.
228      */
229     public static Test suite() {
230 
231         return (new TestSuite(PropertyUtilsTestCase.class));
232 
233     }
234 
235 
236     /**
237      * Tear down instance variables required by this test case.
238      */
239     @Override
240     public void tearDown() {
241 
242         bean = null;
243         beanPackageSubclass = null;
244         beanPrivate = null;
245         beanPrivateSubclass = null;
246         beanPublicSubclass = null;
247 
248         PropertyUtils.resetBeanIntrospectors();
249     }
250 
251 
252 
253     // ------------------------------------------------ Individual Test Methods
254 
255 
256     /**
257      * Test copyProperties() when the origin is a a <code>Map</code>.
258      */
259     public void testCopyPropertiesMap() {
260 
261         final Map<String, Object> map = new HashMap<String, Object>();
262         map.put("booleanProperty", Boolean.FALSE);
263         map.put("doubleProperty", new Double(333.0));
264         map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
265         map.put("floatProperty", new Float((float) 222.0));
266         map.put("intArray", new int[] { 0, 100, 200 });
267         map.put("intProperty", new Integer(111));
268         map.put("longProperty", new Long(444));
269         map.put("shortProperty", new Short((short) 555));
270         map.put("stringProperty", "New String Property");
271 
272         try {
273             PropertyUtils.copyProperties(bean, map);
274         } catch (final Throwable t) {
275             fail("Threw " + t.toString());
276         }
277 
278         // Scalar properties
279         assertEquals("booleanProperty", false,
280                      bean.getBooleanProperty());
281         assertEquals("doubleProperty", 333.0,
282                      bean.getDoubleProperty(), 0.005);
283         assertEquals("floatProperty", (float) 222.0,
284                      bean.getFloatProperty(), (float) 0.005);
285         assertEquals("intProperty", 111,
286                      bean.getIntProperty());
287         assertEquals("longProperty", 444,
288                      bean.getLongProperty());
289         assertEquals("shortProperty", (short) 555,
290                      bean.getShortProperty());
291         assertEquals("stringProperty", "New String Property",
292                      bean.getStringProperty());
293 
294         // Indexed Properties
295         final String dupProperty[] = bean.getDupProperty();
296         assertNotNull("dupProperty present", dupProperty);
297         assertEquals("dupProperty length", 3, dupProperty.length);
298         assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
299         assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
300         assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
301         final int intArray[] = bean.getIntArray();
302         assertNotNull("intArray present", intArray);
303         assertEquals("intArray length", 3, intArray.length);
304         assertEquals("intArray[0]", 0, intArray[0]);
305         assertEquals("intArray[1]", 100, intArray[1]);
306         assertEquals("intArray[2]", 200, intArray[2]);
307 
308     }
309 
310 
311     /**
312      * Test the describe() method.
313      */
314     public void testDescribe() {
315 
316         Map<String, Object> map = null;
317         try {
318             map = PropertyUtils.describe(bean);
319         } catch (final Exception e) {
320             fail("Threw exception " + e);
321         }
322 
323         // Verify existence of all the properties that should be present
324         for (String describe : describes) {
325             assertTrue("Property '" + describe + "' is present",
326                        map.containsKey(describe));
327         }
328         assertTrue("Property 'writeOnlyProperty' is not present",
329                    !map.containsKey("writeOnlyProperty"));
330 
331         // Verify the values of scalar properties
332         assertEquals("Value of 'booleanProperty'",
333                      Boolean.TRUE, map.get("booleanProperty"));
334         assertEquals("Value of 'doubleProperty'",
335                      new Double(321.0), map.get("doubleProperty"));
336         assertEquals("Value of 'floatProperty'",
337                      new Float((float) 123.0), map.get("floatProperty"));
338         assertEquals("Value of 'intProperty'",
339                      new Integer(123), map.get("intProperty"));
340         assertEquals("Value of 'longProperty'",
341                      new Long(321), map.get("longProperty"));
342         assertEquals("Value of 'shortProperty'",
343                      new Short((short) 987), map.get("shortProperty"));
344         assertEquals("Value of 'stringProperty'",
345                      "This is a string",
346                      (String) map.get("stringProperty"));
347 
348     }
349 
350 
351     /**
352      * Corner cases on getPropertyDescriptor invalid arguments.
353      */
354     public void testGetDescriptorArguments() {
355 
356         try {
357             PropertyUtils.getPropertyDescriptor(null, "stringProperty");
358             fail("Should throw IllegalArgumentException 1");
359         } catch (final IllegalArgumentException e) {
360             // Expected response
361         } catch (final Throwable t) {
362             fail("Threw " + t + " instead of IllegalArgumentException 1");
363         }
364 
365         try {
366             PropertyUtils.getPropertyDescriptor(bean, null);
367             fail("Should throw IllegalArgumentException 2");
368         } catch (final IllegalArgumentException e) {
369             // Expected response
370         } catch (final Throwable t) {
371             fail("Threw " + t + " instead of IllegalArgumentException 2");
372         }
373 
374     }
375 
376 
377     /**
378      * Positive getPropertyDescriptor on property <code>booleanProperty</code>.
379      */
380     public void testGetDescriptorBoolean() {
381 
382         testGetDescriptorBase("booleanProperty", "getBooleanProperty",
383                 "setBooleanProperty");
384 
385     }
386 
387 
388     /**
389      * Positive getPropertyDescriptor on property <code>doubleProperty</code>.
390      */
391     public void testGetDescriptorDouble() {
392 
393         testGetDescriptorBase("doubleProperty", "getDoubleProperty",
394                 "setDoubleProperty");
395 
396     }
397 
398 
399     /**
400      * Positive getPropertyDescriptor on property <code>floatProperty</code>.
401      */
402     public void testGetDescriptorFloat() {
403 
404         testGetDescriptorBase("floatProperty", "getFloatProperty",
405                 "setFloatProperty");
406 
407     }
408 
409 
410     /**
411      * Positive getPropertyDescriptor on property <code>intProperty</code>.
412      */
413     public void testGetDescriptorInt() {
414 
415         testGetDescriptorBase("intProperty", "getIntProperty",
416                 "setIntProperty");
417 
418     }
419 
420 
421     /**
422      * <p>Negative tests on an invalid property with two different boolean
423      * getters (which is fine, according to the JavaBeans spec) but a
424      * String setter instead of a boolean setter.</p>
425      *
426      * <p>Although one could logically argue that this combination of method
427      * signatures should not identify a property at all, there is a sentence
428      * in Section 8.3.1 making it clear that the behavior tested for here
429      * is correct:  "If we find only one of these methods, then we regard
430      * it as defining either a read-only or write-only property called
431      * <em>&lt;property-name&gt;</em>.</p>
432      */
433     public void testGetDescriptorInvalidBoolean() throws Exception {
434 
435     final PropertyDescriptor pd =
436         PropertyUtils.getPropertyDescriptor(bean, "invalidBoolean");
437     assertNotNull("invalidBoolean is a property", pd);
438     assertNotNull("invalidBoolean has a getter method",
439               pd.getReadMethod());
440     assertNull("invalidBoolean has no write method",
441            pd.getWriteMethod());
442     assertTrue("invalidBoolean getter method is isInvalidBoolean or getInvalidBoolean",
443            Arrays.asList("isInvalidBoolean", "getInvalidBoolean")
444            .contains(pd.getReadMethod().getName()));
445     }
446 
447 
448     /**
449      * Positive getPropertyDescriptor on property <code>longProperty</code>.
450      */
451     public void testGetDescriptorLong() {
452 
453         testGetDescriptorBase("longProperty", "getLongProperty",
454                 "setLongProperty");
455 
456     }
457 
458     /**
459      * Test getting mapped descriptor with periods in the key.
460      */
461     public void testGetDescriptorMappedPeriods() {
462 
463         bean.getMappedIntProperty("xyz"); // initializes mappedIntProperty
464 
465         PropertyDescriptor desc;
466         final Integer testIntegerValue = new Integer(1234);
467 
468         bean.setMappedIntProperty("key.with.a.dot", testIntegerValue.intValue());
469         assertEquals("Can retrieve directly",
470                      testIntegerValue,
471                      new Integer(bean.getMappedIntProperty("key.with.a.dot")));
472         try {
473             desc = PropertyUtils.getPropertyDescriptor
474                          (bean, "mappedIntProperty(key.with.a.dot)");
475             assertEquals("Check descriptor type (A)",
476                          Integer.TYPE,
477                          ((MappedPropertyDescriptor)desc).getMappedPropertyType());
478         } catch (final Exception e) {
479             fail("Threw exception (A): " + e);
480         }
481 
482         bean.setMappedObjects("nested.property", new TestBean(testIntegerValue.intValue()));
483         assertEquals("Can retrieve directly",
484                       testIntegerValue,
485                       new Integer(((TestBean)bean.getMappedObjects("nested.property")).getIntProperty()));
486         try {
487             desc = PropertyUtils.getPropertyDescriptor
488                          (bean, "mappedObjects(nested.property).intProperty");
489             assertEquals("Check descriptor type (B)",
490                          Integer.TYPE,
491                          desc.getPropertyType());
492         } catch (final Exception e) {
493             fail("Threw exception (B): " + e);
494         }
495     }
496 
497 
498     /**
499      * Positive getPropertyDescriptor on property
500      * <code>readOnlyProperty</code>.
501      */
502     public void testGetDescriptorReadOnly() {
503 
504         testGetDescriptorBase("readOnlyProperty", "getReadOnlyProperty",
505                 null);
506 
507     }
508 
509 
510     /**
511      * Positive getPropertyDescriptor on property <code>booleanSecond</code>
512      * that uses an "is" method as the getter.
513      */
514     public void testGetDescriptorSecond() {
515 
516         testGetDescriptorBase("booleanSecond", "isBooleanSecond",
517                 "setBooleanSecond");
518 
519     }
520 
521 
522     /**
523      * Positive getPropertyDescriptor on property <code>shortProperty</code>.
524      */
525     public void testGetDescriptorShort() {
526 
527         testGetDescriptorBase("shortProperty", "getShortProperty",
528                 "setShortProperty");
529 
530     }
531 
532 
533     /**
534      * Positive getPropertyDescriptor on property <code>stringProperty</code>.
535      */
536     public void testGetDescriptorString() {
537 
538         testGetDescriptorBase("stringProperty", "getStringProperty",
539                 "setStringProperty");
540 
541     }
542 
543 
544     /**
545      * Negative getPropertyDescriptor on property <code>unknown</code>.
546      */
547     public void testGetDescriptorUnknown() {
548 
549         testGetDescriptorBase("unknown", null, null);
550 
551     }
552 
553 
554     /**
555      * Positive getPropertyDescriptor on property
556      * <code>writeOnlyProperty</code>.
557      */
558     public void testGetDescriptorWriteOnly() {
559 
560         testGetDescriptorBase("writeOnlyProperty", null,
561                 "setWriteOnlyProperty");
562 
563     }
564 
565 
566     /**
567      * Positive test for getPropertyDescriptors().  Each property name
568      * listed in <code>properties</code> should be returned exactly once.
569      */
570     public void testGetDescriptors() {
571 
572         final PropertyDescriptor pd[] =
573                 PropertyUtils.getPropertyDescriptors(bean);
574         assertNotNull("Got descriptors", pd);
575         final int count[] = new int[properties.length];
576         for (PropertyDescriptor element : pd) {
577             final String name = element.getName();
578             for (int j = 0; j < properties.length; j++) {
579                 if (name.equals(properties[j])) {
580                     count[j]++;
581                 }
582             }
583         }
584         for (int j = 0; j < properties.length; j++) {
585             if (count[j] < 0) {
586                 fail("Missing property " + properties[j]);
587             } else if (count[j] > 1) {
588                 fail("Duplicate property " + properties[j]);
589             }
590         }
591 
592     }
593 
594 
595     /**
596      * Corner cases on getPropertyDescriptors invalid arguments.
597      */
598     public void testGetDescriptorsArguments() {
599 
600         try {
601             PropertyUtils.getPropertyDescriptors(null);
602             fail("Should throw IllegalArgumentException");
603         } catch (final IllegalArgumentException e) {
604             // Expected response
605         } catch (final Throwable t) {
606             fail("Threw " + t + " instead of IllegalArgumentException");
607         }
608 
609     }
610 
611 
612     /**
613      * Corner cases on getIndexedProperty invalid arguments.
614      */
615     public void testGetIndexedArguments() {
616 
617         // Use explicit index argument
618 
619         try {
620             PropertyUtils.getIndexedProperty(null, "intArray", 0);
621             fail("Should throw IllegalArgumentException 1");
622         } catch (final IllegalArgumentException e) {
623             // Expected response
624         } catch (final Throwable t) {
625             fail("Threw " + t + " instead of IllegalArgumentException 1");
626         }
627 
628         try {
629             PropertyUtils.getIndexedProperty(bean, null, 0);
630             fail("Should throw IllegalArgumentException 2");
631         } catch (final IllegalArgumentException e) {
632             // Expected response
633         } catch (final Throwable t) {
634             fail("Threw " + t + " instead of IllegalArgumentException 2");
635         }
636 
637         // Use index expression
638 
639         try {
640             PropertyUtils.getIndexedProperty(null,
641                     "intArray[0]");
642             fail("Should throw IllegalArgumentException 3");
643         } catch (final IllegalArgumentException e) {
644             // Expected response
645         } catch (final Throwable t) {
646             fail("Threw " + t + " instead of IllegalArgumentException 3");
647         }
648 
649         try {
650             PropertyUtils.getIndexedProperty(bean, "[0]");
651             fail("Should throw NoSuchMethodException 4");
652         } catch (final NoSuchMethodException e) {
653             // Expected response
654         } catch (final Throwable t) {
655             fail("Threw " + t + " instead of NoSuchMethodException 4");
656         }
657 
658         try {
659             PropertyUtils.getIndexedProperty(bean, "intArray");
660             fail("Should throw IllegalArgumentException 5");
661         } catch (final IllegalArgumentException e) {
662             // Expected response
663         } catch (final Throwable t) {
664             fail("Threw " + t + " instead of IllegalArgumentException 5");
665         }
666 
667         // Use explicit index argument
668 
669         try {
670             PropertyUtils.getIndexedProperty(null, "intIndexed", 0);
671             fail("Should throw IllegalArgumentException 1");
672         } catch (final IllegalArgumentException e) {
673             // Expected response
674         } catch (final Throwable t) {
675             fail("Threw " + t + " instead of IllegalArgumentException 1");
676         }
677 
678         try {
679             PropertyUtils.getIndexedProperty(bean, null, 0);
680             fail("Should throw IllegalArgumentException 2");
681         } catch (final IllegalArgumentException e) {
682             // Expected response
683         } catch (final Throwable t) {
684             fail("Threw " + t + " instead of IllegalArgumentException 2");
685         }
686 
687         // Use index expression
688 
689         try {
690             PropertyUtils.getIndexedProperty(null,
691                     "intIndexed[0]");
692             fail("Should throw IllegalArgumentException 3");
693         } catch (final IllegalArgumentException e) {
694             // Expected response
695         } catch (final Throwable t) {
696             fail("Threw " + t + " instead of IllegalArgumentException 3");
697         }
698 
699         try {
700             PropertyUtils.getIndexedProperty(bean, "[0]");
701             fail("Should throw NoSuchMethodException 4");
702         } catch (final NoSuchMethodException e) {
703             // Expected response
704         } catch (final Throwable t) {
705             fail("Threw " + t + " instead of NoSuchMethodException 4");
706         }
707 
708         try {
709             PropertyUtils.getIndexedProperty(bean, "intIndexed");
710             fail("Should throw IllegalArgumentException 5");
711         } catch (final IllegalArgumentException e) {
712             // Expected response
713         } catch (final Throwable t) {
714             fail("Threw " + t + " instead of IllegalArgumentException 5");
715         }
716 
717     }
718 
719 
720     /**
721      * Positive and negative tests on getIndexedProperty valid arguments.
722      */
723     public void testGetIndexedValues() {
724 
725         Object value = null;
726 
727         // Use explicit key argument
728 
729         for (int i = 0; i < 5; i++) {
730 
731             try {
732                 value = PropertyUtils.getIndexedProperty
733                     (bean, "dupProperty", i);
734                 assertNotNull("dupProperty returned value " + i, value);
735                 assertTrue("dupProperty returned String " + i,
736                         value instanceof String);
737                 assertEquals("dupProperty returned correct " + i,
738                              "Dup " + i,
739                              (String) value);
740             } catch (final Throwable t) {
741                 fail("dupProperty " + i + " threw " + t);
742             }
743 
744             try {
745                 value =
746                         PropertyUtils.getIndexedProperty(bean, "intArray", i);
747                 assertNotNull("intArray returned value " + i, value);
748                 assertTrue("intArray returned Integer " + i,
749                         value instanceof Integer);
750                 assertEquals("intArray returned correct " + i, i * 10,
751                         ((Integer) value).intValue());
752             } catch (final Throwable t) {
753                 fail("intArray " + i + " threw " + t);
754             }
755 
756             try {
757                 value =
758                         PropertyUtils.getIndexedProperty(bean, "intIndexed", i);
759                 assertNotNull("intIndexed returned value " + i, value);
760                 assertTrue("intIndexed returned Integer " + i,
761                         value instanceof Integer);
762                 assertEquals("intIndexed returned correct " + i, i * 10,
763                         ((Integer) value).intValue());
764             } catch (final Throwable t) {
765                 fail("intIndexed " + i + " threw " + t);
766             }
767 
768             try {
769                 value =
770                         PropertyUtils.getIndexedProperty(bean, "listIndexed", i);
771                 assertNotNull("listIndexed returned value " + i, value);
772                 assertTrue("list returned String " + i,
773                         value instanceof String);
774                 assertEquals("listIndexed returned correct " + i,
775                         "String " + i, (String) value);
776             } catch (final Throwable t) {
777                 fail("listIndexed " + i + " threw " + t);
778             }
779 
780             try {
781                 value =
782                         PropertyUtils.getIndexedProperty(bean, "stringArray", i);
783                 assertNotNull("stringArray returned value " + i, value);
784                 assertTrue("stringArray returned String " + i,
785                         value instanceof String);
786                 assertEquals("stringArray returned correct " + i,
787                         "String " + i, (String) value);
788             } catch (final Throwable t) {
789                 fail("stringArray " + i + " threw " + t);
790             }
791 
792             try {
793                 value =
794                         PropertyUtils.getIndexedProperty(bean, "stringIndexed", i);
795                 assertNotNull("stringIndexed returned value " + i, value);
796                 assertTrue("stringIndexed returned String " + i,
797                         value instanceof String);
798                 assertEquals("stringIndexed returned correct " + i,
799                         "String " + i, (String) value);
800             } catch (final Throwable t) {
801                 fail("stringIndexed " + i + " threw " + t);
802             }
803 
804         }
805 
806         // Use key expression
807 
808         for (int i = 0; i < 5; i++) {
809 
810             try {
811                 value = PropertyUtils.getIndexedProperty
812                     (bean, "dupProperty[" + i + "]");
813                 assertNotNull("dupProperty returned value " + i, value);
814                 assertTrue("dupProperty returned String " + i,
815                         value instanceof String);
816                 assertEquals("dupProperty returned correct " + i,
817                              "Dup " + i,
818                              (String) value);
819             } catch (final Throwable t) {
820                 fail("dupProperty " + i + " threw " + t);
821             }
822 
823             try {
824                 value =
825                         PropertyUtils.getIndexedProperty(bean,
826                                 "intArray[" + i + "]");
827                 assertNotNull("intArray returned value " + i, value);
828                 assertTrue("intArray returned Integer " + i,
829                         value instanceof Integer);
830                 assertEquals("intArray returned correct " + i, i * 10,
831                         ((Integer) value).intValue());
832             } catch (final Throwable t) {
833                 fail("intArray " + i + " threw " + t);
834             }
835 
836             try {
837                 value =
838                         PropertyUtils.getIndexedProperty(bean,
839                                 "intIndexed[" + i + "]");
840                 assertNotNull("intIndexed returned value " + i, value);
841                 assertTrue("intIndexed returned Integer " + i,
842                         value instanceof Integer);
843                 assertEquals("intIndexed returned correct " + i, i * 10,
844                         ((Integer) value).intValue());
845             } catch (final Throwable t) {
846                 fail("intIndexed " + i + " threw " + t);
847             }
848 
849             try {
850                 value =
851                         PropertyUtils.getIndexedProperty(bean,
852                                 "listIndexed[" + i + "]");
853                 assertNotNull("listIndexed returned value " + i, value);
854                 assertTrue("listIndexed returned String " + i,
855                         value instanceof String);
856                 assertEquals("listIndexed returned correct " + i,
857                         "String " + i, (String) value);
858             } catch (final Throwable t) {
859                 fail("listIndexed " + i + " threw " + t);
860             }
861 
862             try {
863                 value =
864                         PropertyUtils.getIndexedProperty(bean,
865                                 "stringArray[" + i + "]");
866                 assertNotNull("stringArray returned value " + i, value);
867                 assertTrue("stringArray returned String " + i,
868                         value instanceof String);
869                 assertEquals("stringArray returned correct " + i,
870                         "String " + i, (String) value);
871             } catch (final Throwable t) {
872                 fail("stringArray " + i + " threw " + t);
873             }
874 
875             try {
876                 value =
877                         PropertyUtils.getIndexedProperty(bean,
878                                 "stringIndexed[" + i + "]");
879                 assertNotNull("stringIndexed returned value " + i, value);
880                 assertTrue("stringIndexed returned String " + i,
881                         value instanceof String);
882                 assertEquals("stringIndexed returned correct " + i,
883                         "String " + i, (String) value);
884             } catch (final Throwable t) {
885                 fail("stringIndexed " + i + " threw " + t);
886             }
887 
888         }
889 
890         // Index out of bounds tests
891 
892         try {
893             value =
894                     PropertyUtils.getIndexedProperty(bean,
895                             "dupProperty", -1);
896             fail("Should have thrown ArrayIndexOutOfBoundsException");
897         } catch (final ArrayIndexOutOfBoundsException t) {
898             // Expected results
899         } catch (final Throwable t) {
900             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
901         }
902 
903         try {
904             value =
905                     PropertyUtils.getIndexedProperty(bean,
906                             "dupProperty", 5);
907             fail("Should have thrown ArrayIndexOutOfBoundsException");
908         } catch (final ArrayIndexOutOfBoundsException t) {
909             // Expected results
910         } catch (final Throwable t) {
911             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
912         }
913 
914         try {
915             value =
916                     PropertyUtils.getIndexedProperty(bean,
917                             "intArray", -1);
918             fail("Should have thrown ArrayIndexOutOfBoundsException");
919         } catch (final ArrayIndexOutOfBoundsException t) {
920             // Expected results
921         } catch (final Throwable t) {
922             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
923         }
924 
925         try {
926             value =
927                     PropertyUtils.getIndexedProperty(bean,
928                             "intArray", 5);
929             fail("Should have thrown ArrayIndexOutOfBoundsException");
930         } catch (final ArrayIndexOutOfBoundsException t) {
931             // Expected results
932         } catch (final Throwable t) {
933             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
934         }
935 
936         try {
937             value =
938                     PropertyUtils.getIndexedProperty(bean,
939                             "intIndexed", -1);
940             fail("Should have thrown ArrayIndexOutOfBoundsException");
941         } catch (final ArrayIndexOutOfBoundsException t) {
942             // Expected results
943         } catch (final Throwable t) {
944             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
945         }
946 
947         try {
948             value =
949                     PropertyUtils.getIndexedProperty(bean,
950                             "intIndexed", 5);
951             fail("Should have thrown ArrayIndexOutOfBoundsException");
952         } catch (final ArrayIndexOutOfBoundsException t) {
953             // Expected results
954         } catch (final Throwable t) {
955             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
956         }
957 
958         try {
959             value =
960                     PropertyUtils.getIndexedProperty(bean,
961                             "listIndexed", -1);
962             fail("Should have thrown IndexOutOfBoundsException");
963         } catch (final IndexOutOfBoundsException t) {
964             // Expected results
965         } catch (final Throwable t) {
966             fail("Threw " + t + " instead of IndexOutOfBoundsException");
967         }
968 
969         try {
970             value =
971                     PropertyUtils.getIndexedProperty(bean,
972                             "listIndexed", 5);
973             fail("Should have thrown IndexOutOfBoundsException");
974         } catch (final IndexOutOfBoundsException t) {
975             // Expected results
976         } catch (final Throwable t) {
977             fail("Threw " + t + " instead of IndexOutOfBoundsException");
978         }
979 
980         try {
981             value =
982                     PropertyUtils.getIndexedProperty(bean,
983                             "stringArray", -1);
984             fail("Should have thrown ArrayIndexOutOfBoundsException");
985         } catch (final ArrayIndexOutOfBoundsException t) {
986             // Expected results
987         } catch (final Throwable t) {
988             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
989         }
990 
991         try {
992             value =
993                     PropertyUtils.getIndexedProperty(bean,
994                             "stringArray", 5);
995             fail("Should have thrown ArrayIndexOutOfBoundsException");
996         } catch (final ArrayIndexOutOfBoundsException t) {
997             // Expected results
998         } catch (final Throwable t) {
999             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
1000         }
1001 
1002         try {
1003             value =
1004                     PropertyUtils.getIndexedProperty(bean,
1005                             "stringIndexed", -1);
1006             fail("Should have thrown ArrayIndexOutOfBoundsException");
1007         } catch (final ArrayIndexOutOfBoundsException t) {
1008             // Expected results
1009         } catch (final Throwable t) {
1010             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
1011         }
1012 
1013         try {
1014             value =
1015                     PropertyUtils.getIndexedProperty(bean,
1016                             "stringIndexed", 5);
1017             fail("Should have thrown ArrayIndexOutOfBoundsException");
1018         } catch (final ArrayIndexOutOfBoundsException t) {
1019             // Expected results
1020         } catch (final Throwable t) {
1021             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
1022         }
1023 
1024     }
1025 
1026 
1027     /**
1028      * Test getting an indexed value out of a multi-dimensional array
1029      */
1030     public void testGetIndexedArray() {
1031         final String[] firstArray = new String[] {"FIRST-1", "FIRST-2", "FIRST-3"};
1032         final String[] secondArray = new String[] {"SECOND-1", "SECOND-2", "SECOND-3",  "SECOND-4"};
1033         final String[][] mainArray = {firstArray, secondArray};
1034         final TestBean bean = new TestBean(mainArray);
1035         try {
1036             assertEquals("firstArray[0]", firstArray[0],  PropertyUtils.getProperty(bean, "string2dArray[0][0]"));
1037             assertEquals("firstArray[1]", firstArray[1],  PropertyUtils.getProperty(bean, "string2dArray[0][1]"));
1038             assertEquals("firstArray[2]", firstArray[2],  PropertyUtils.getProperty(bean, "string2dArray[0][2]"));
1039             assertEquals("secondArray[0]", secondArray[0], PropertyUtils.getProperty(bean, "string2dArray[1][0]"));
1040             assertEquals("secondArray[1]", secondArray[1], PropertyUtils.getProperty(bean, "string2dArray[1][1]"));
1041             assertEquals("secondArray[2]", secondArray[2], PropertyUtils.getProperty(bean, "string2dArray[1][2]"));
1042             assertEquals("secondArray[3]", secondArray[3], PropertyUtils.getProperty(bean, "string2dArray[1][3]"));
1043         } catch (final Throwable t) {
1044             fail("Threw " + t + "");
1045         }
1046     }
1047 
1048     /**
1049      * Test getting an indexed value out of List of Lists
1050      */
1051     public void testGetIndexedList() {
1052         final String[] firstArray = new String[] {"FIRST-1", "FIRST-2", "FIRST-3"};
1053         final String[] secondArray = new String[] {"SECOND-1", "SECOND-2", "SECOND-3",  "SECOND-4"};
1054         final List<Object> mainList = new ArrayList<Object>();
1055         mainList.add(Arrays.asList(firstArray));
1056         mainList.add(Arrays.asList(secondArray));
1057         final TestBean bean = new TestBean(mainList);
1058         try {
1059             assertEquals("firstArray[0]", firstArray[0],  PropertyUtils.getProperty(bean, "listIndexed[0][0]"));
1060             assertEquals("firstArray[1]", firstArray[1],  PropertyUtils.getProperty(bean, "listIndexed[0][1]"));
1061             assertEquals("firstArray[2]", firstArray[2],  PropertyUtils.getProperty(bean, "listIndexed[0][2]"));
1062             assertEquals("secondArray[0]", secondArray[0], PropertyUtils.getProperty(bean, "listIndexed[1][0]"));
1063             assertEquals("secondArray[1]", secondArray[1], PropertyUtils.getProperty(bean, "listIndexed[1][1]"));
1064             assertEquals("secondArray[2]", secondArray[2], PropertyUtils.getProperty(bean, "listIndexed[1][2]"));
1065             assertEquals("secondArray[3]", secondArray[3], PropertyUtils.getProperty(bean, "listIndexed[1][3]"));
1066         } catch (final Throwable t) {
1067             fail("Threw " + t + "");
1068         }
1069     }
1070 
1071     /**
1072      * Test getting a value out of a mapped Map
1073      */
1074     public void testGetIndexedMap() {
1075         final Map<String, Object> firstMap  = new HashMap<String, Object>();
1076         firstMap.put("FIRST-KEY-1", "FIRST-VALUE-1");
1077         firstMap.put("FIRST-KEY-2", "FIRST-VALUE-2");
1078         final Map<String, Object> secondMap  = new HashMap<String, Object>();
1079         secondMap.put("SECOND-KEY-1", "SECOND-VALUE-1");
1080         secondMap.put("SECOND-KEY-2", "SECOND-VALUE-2");
1081 
1082         final List<Object> mainList   = new ArrayList<Object>();
1083         mainList.add(firstMap);
1084         mainList.add(secondMap);
1085         final TestBean bean = new TestBean(mainList);
1086         try {
1087             assertEquals("listIndexed[0](FIRST-KEY-1)",  "FIRST-VALUE-1",   PropertyUtils.getProperty(bean, "listIndexed[0](FIRST-KEY-1)"));
1088             assertEquals("listIndexed[0](FIRST-KEY-2)",  "FIRST-VALUE-2",   PropertyUtils.getProperty(bean, "listIndexed[0](FIRST-KEY-2)"));
1089             assertEquals("listIndexed[1](SECOND-KEY-1)", "SECOND-VALUE-1",  PropertyUtils.getProperty(bean, "listIndexed[1](SECOND-KEY-1)"));
1090             assertEquals("listIndexed[1](SECOND-KEY-2)", "SECOND-VALUE-2",  PropertyUtils.getProperty(bean, "listIndexed[1](SECOND-KEY-2)"));
1091         } catch (final Throwable t) {
1092             fail("Threw " + t + "");
1093         }
1094     }
1095 
1096     /**
1097      * Corner cases on getMappedProperty invalid arguments.
1098      */
1099     public void testGetMappedArguments() {
1100 
1101         // Use explicit key argument
1102 
1103         try {
1104             PropertyUtils.getMappedProperty(null, "mappedProperty",
1105                     "First Key");
1106             fail("Should throw IllegalArgumentException 1");
1107         } catch (final IllegalArgumentException e) {
1108             // Expected response
1109         } catch (final Throwable t) {
1110             fail("Threw " + t + " instead of IllegalArgumentException 1");
1111         }
1112 
1113         try {
1114             PropertyUtils.getMappedProperty(bean, null, "First Key");
1115             fail("Should throw IllegalArgumentException 2");
1116         } catch (final IllegalArgumentException e) {
1117             // Expected response
1118         } catch (final Throwable t) {
1119             fail("Threw " + t + " instead of IllegalArgumentException 2");
1120         }
1121 
1122         try {
1123             PropertyUtils.getMappedProperty(bean, "mappedProperty", null);
1124             fail("Should throw IllegalArgumentException 3");
1125         } catch (final IllegalArgumentException e) {
1126             // Expected response
1127         } catch (final Throwable t) {
1128             fail("Threw " + t + " instead of IllegalArgumentException 3");
1129         }
1130 
1131         // Use key expression
1132 
1133         try {
1134             PropertyUtils.getMappedProperty(null,
1135                     "mappedProperty(First Key)");
1136             fail("Should throw IllegalArgumentException 4");
1137         } catch (final IllegalArgumentException e) {
1138             // Expected response
1139         } catch (final Throwable t) {
1140             fail("Threw " + t + " instead of IllegalArgumentException 4");
1141         }
1142 
1143         try {
1144             PropertyUtils.getMappedProperty(bean, "(Second Key)");
1145             fail("Should throw IllegalArgumentException 5");
1146         } catch (final NoSuchMethodException e) {
1147             // Expected response
1148         } catch (final Throwable t) {
1149             fail("Threw " + t + " instead of NoSuchMethodException 5");
1150         }
1151 
1152         try {
1153             PropertyUtils.getMappedProperty(bean, "mappedProperty");
1154             fail("Should throw IllegalArgumentException 6");
1155         } catch (final IllegalArgumentException e) {
1156             // Expected response
1157         } catch (final Throwable t) {
1158             fail("Threw " + t + " instead of IllegalArgumentException 6");
1159         }
1160 
1161     }
1162 
1163     /**
1164      * Test getting an indexed value out of a mapped array
1165      */
1166     public void testGetMappedArray() {
1167         final TestBean bean = new TestBean();
1168         final String[] array = new String[] {"abc", "def", "ghi"};
1169         bean.getMapProperty().put("mappedArray", array);
1170         try {
1171             assertEquals("abc", PropertyUtils.getProperty(bean, "mapProperty(mappedArray)[0]"));
1172             assertEquals("def", PropertyUtils.getProperty(bean, "mapProperty(mappedArray)[1]"));
1173             assertEquals("ghi", PropertyUtils.getProperty(bean, "mapProperty(mappedArray)[2]"));
1174         } catch (final Throwable t) {
1175             fail("Threw " + t + "");
1176         }
1177     }
1178 
1179     /**
1180      * Test getting an indexed value out of a mapped List
1181      */
1182     public void testGetMappedList() {
1183         final TestBean bean = new TestBean();
1184         final List<Object> list = new ArrayList<Object>();
1185         list.add("klm");
1186         list.add("nop");
1187         list.add("qrs");
1188         bean.getMapProperty().put("mappedList", list);
1189         try {
1190             assertEquals("klm", PropertyUtils.getProperty(bean, "mapProperty(mappedList)[0]"));
1191             assertEquals("nop", PropertyUtils.getProperty(bean, "mapProperty(mappedList)[1]"));
1192             assertEquals("qrs", PropertyUtils.getProperty(bean, "mapProperty(mappedList)[2]"));
1193         } catch (final Throwable t) {
1194             fail("Threw " + t + "");
1195         }
1196     }
1197 
1198     /**
1199      * Test getting a value out of a mapped Map
1200      */
1201     public void testGetMappedMap() {
1202         final TestBean bean = new TestBean();
1203         final Map<String, Object> map = new HashMap<String, Object>();
1204         map.put("sub-key-1", "sub-value-1");
1205         map.put("sub-key-2", "sub-value-2");
1206         map.put("sub-key-3", "sub-value-3");
1207         bean.getMapProperty().put("mappedMap", map);
1208         try {
1209             assertEquals("sub-value-1", PropertyUtils.getProperty(bean, "mapProperty(mappedMap)(sub-key-1)"));
1210             assertEquals("sub-value-2", PropertyUtils.getProperty(bean, "mapProperty(mappedMap)(sub-key-2)"));
1211             assertEquals("sub-value-3", PropertyUtils.getProperty(bean, "mapProperty(mappedMap)(sub-key-3)"));
1212         } catch (final Throwable t) {
1213             fail("Threw " + t + "");
1214         }
1215     }
1216 
1217     /**
1218      * Test getting mapped values with periods in the key.
1219      */
1220     public void testGetMappedPeriods() {
1221 
1222         bean.setMappedProperty("key.with.a.dot", "Special Value");
1223         assertEquals("Can retrieve directly",
1224                      "Special Value",
1225                      bean.getMappedProperty("key.with.a.dot"));
1226         try {
1227             assertEquals("Can retrieve via getMappedProperty",
1228                          "Special Value",
1229                          PropertyUtils.getMappedProperty
1230                          (bean, "mappedProperty", "key.with.a.dot"));
1231         } catch (final Exception e) {
1232             fail("Thew exception: " + e);
1233         }
1234         try {
1235             assertEquals("Can retrieve via getNestedProperty",
1236                          "Special Value",
1237                          PropertyUtils.getNestedProperty
1238                          (bean, "mappedProperty(key.with.a.dot)"));
1239         } catch (final Exception e) {
1240             fail("Thew exception: " + e);
1241         }
1242 
1243         bean.setMappedObjects("nested.property", new TestBean());
1244         assertNotNull("Can retrieve directly",
1245                       bean.getMappedObjects("nested.property"));
1246         try {
1247             assertEquals("Can retrieve nested",
1248                          "This is a string",
1249                          PropertyUtils.getNestedProperty
1250                          (bean,
1251                           "mappedObjects(nested.property).stringProperty"));
1252         } catch (final Exception e) {
1253             fail("Thew exception: " + e);
1254         }
1255 
1256         try
1257         {
1258             assertEquals("Can't retrieved nested with mapped property",
1259                          "Mapped Value",
1260                          PropertyUtils.getNestedProperty(
1261                              bean,"mappedNested.value(Mapped Key)"));
1262         } catch (final Exception e)
1263         {
1264             fail("Thew exception: " + e);
1265         }
1266     }
1267 
1268 
1269     /**
1270      * Test getting mapped values with slashes in the key.  This is different
1271      * from periods because slashes are not syntactically significant.
1272      */
1273     public void testGetMappedSlashes() {
1274 
1275         bean.setMappedProperty("key/with/a/slash", "Special Value");
1276         assertEquals("Can retrieve directly",
1277                      "Special Value",
1278                      bean.getMappedProperty("key/with/a/slash"));
1279         try {
1280             assertEquals("Can retrieve via getMappedProperty",
1281                          "Special Value",
1282                          PropertyUtils.getMappedProperty
1283                          (bean, "mappedProperty", "key/with/a/slash"));
1284         } catch (final Exception e) {
1285             fail("Thew exception: " + e);
1286         }
1287         try {
1288             assertEquals("Can retrieve via getNestedProperty",
1289                          "Special Value",
1290                          PropertyUtils.getNestedProperty
1291                          (bean, "mappedProperty(key/with/a/slash)"));
1292         } catch (final Exception e) {
1293             fail("Thew exception: " + e);
1294         }
1295 
1296         bean.setMappedObjects("nested/property", new TestBean());
1297         assertNotNull("Can retrieve directly",
1298                       bean.getMappedObjects("nested/property"));
1299         try {
1300             assertEquals("Can retrieve nested",
1301                          "This is a string",
1302                          PropertyUtils.getNestedProperty
1303                          (bean,
1304                           "mappedObjects(nested/property).stringProperty"));
1305         } catch (final Exception e) {
1306             fail("Thew exception: " + e);
1307         }
1308 
1309     }
1310 
1311 
1312     /**
1313      * Positive and negative tests on getMappedProperty valid arguments.
1314      */
1315     public void testGetMappedValues() {
1316 
1317         Object value = null;
1318 
1319         // Use explicit key argument
1320 
1321         try {
1322             value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
1323                     "First Key");
1324             assertEquals("Can find first value", "First Value", value);
1325         } catch (final Throwable t) {
1326             fail("Finding first value threw " + t);
1327         }
1328 
1329         try {
1330             value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
1331                     "Second Key");
1332             assertEquals("Can find second value", "Second Value", value);
1333         } catch (final Throwable t) {
1334             fail("Finding second value threw " + t);
1335         }
1336 
1337         try {
1338             value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
1339                     "Third Key");
1340             assertNull("Can not find third value", value);
1341         } catch (final Throwable t) {
1342             fail("Finding third value threw " + t);
1343         }
1344 
1345         // Use key expression with parentheses
1346 
1347         try {
1348             value =
1349                     PropertyUtils.getMappedProperty(bean,
1350                             "mappedProperty(First Key)");
1351             assertEquals("Can find first value", "First Value", value);
1352         } catch (final Throwable t) {
1353             fail("Finding first value threw " + t);
1354         }
1355 
1356         try {
1357             value =
1358                     PropertyUtils.getMappedProperty(bean,
1359                             "mappedProperty(Second Key)");
1360             assertEquals("Can find second value", "Second Value", value);
1361         } catch (final Throwable t) {
1362             fail("Finding second value threw " + t);
1363         }
1364 
1365         try {
1366             value =
1367                     PropertyUtils.getMappedProperty(bean,
1368                             "mappedProperty(Third Key)");
1369             assertNull("Can not find third value", value);
1370         } catch (final Throwable t) {
1371             fail("Finding third value threw " + t);
1372         }
1373 
1374         // Use key expression with dotted syntax
1375 
1376         try {
1377             value =
1378                     PropertyUtils.getNestedProperty(bean,
1379                             "mapProperty.First Key");
1380             assertEquals("Can find first value", "First Value", value);
1381         } catch (final Throwable t) {
1382             fail("Finding first value threw " + t);
1383         }
1384 
1385         try {
1386             value =
1387                     PropertyUtils.getNestedProperty(bean,
1388                             "mapProperty.Second Key");
1389             assertEquals("Can find second value", "Second Value", value);
1390         } catch (final Throwable t) {
1391             fail("Finding second value threw " + t);
1392         }
1393 
1394         try {
1395             value =
1396                     PropertyUtils.getNestedProperty(bean,
1397                             "mapProperty.Third Key");
1398             assertNull("Can not find third value", value);
1399         } catch (final Throwable t) {
1400             fail("Finding third value threw " + t);
1401         }
1402 
1403     }
1404 
1405 
1406     /**
1407      * Corner cases on getNestedProperty invalid arguments.
1408      */
1409     public void testGetNestedArguments() {
1410 
1411         try {
1412             PropertyUtils.getNestedProperty(null, "stringProperty");
1413             fail("Should throw IllegalArgumentException 1");
1414         } catch (final IllegalArgumentException e) {
1415             // Expected response
1416         } catch (final Throwable t) {
1417             fail("Threw " + t + " instead of IllegalArgumentException 1");
1418         }
1419 
1420         try {
1421             PropertyUtils.getNestedProperty(bean, null);
1422             fail("Should throw IllegalArgumentException 2");
1423         } catch (final IllegalArgumentException e) {
1424             // Expected response
1425         } catch (final Throwable t) {
1426             fail("Threw " + t + " instead of IllegalArgumentException 2");
1427         }
1428 
1429     }
1430 
1431 
1432     /**
1433      * Test getNestedProperty on a boolean property.
1434      */
1435     public void testGetNestedBoolean() {
1436 
1437         try {
1438             final Object value =
1439                     PropertyUtils.getNestedProperty
1440                     (bean, "nested.booleanProperty");
1441             assertNotNull("Got a value", value);
1442             assertTrue("Got correct type", (value instanceof Boolean));
1443             assertTrue("Got correct value",
1444                     ((Boolean) value).booleanValue() ==
1445                     bean.getNested().getBooleanProperty());
1446         } catch (final IllegalAccessException e) {
1447             fail("IllegalAccessException");
1448         } catch (final IllegalArgumentException e) {
1449             fail("IllegalArgumentException");
1450         } catch (final InvocationTargetException e) {
1451             fail("InvocationTargetException");
1452         } catch (final NoSuchMethodException e) {
1453             fail("NoSuchMethodException");
1454         }
1455 
1456     }
1457 
1458 
1459     /**
1460      * Test getNestedProperty on a double property.
1461      */
1462     public void testGetNestedDouble() {
1463 
1464         try {
1465             final Object value =
1466                     PropertyUtils.getNestedProperty
1467                     (bean, "nested.doubleProperty");
1468             assertNotNull("Got a value", value);
1469             assertTrue("Got correct type", (value instanceof Double));
1470             assertEquals("Got correct value",
1471                     ((Double) value).doubleValue(),
1472                     bean.getNested().getDoubleProperty(),
1473                     0.005);
1474         } catch (final IllegalAccessException e) {
1475             fail("IllegalAccessException");
1476         } catch (final IllegalArgumentException e) {
1477             fail("IllegalArgumentException");
1478         } catch (final InvocationTargetException e) {
1479             fail("InvocationTargetException");
1480         } catch (final NoSuchMethodException e) {
1481             fail("NoSuchMethodException");
1482         }
1483 
1484     }
1485 
1486 
1487     /**
1488      * Test getNestedProperty on a float property.
1489      */
1490     public void testGetNestedFloat() {
1491 
1492         try {
1493             final Object value =
1494                     PropertyUtils.getNestedProperty
1495                     (bean, "nested.floatProperty");
1496             assertNotNull("Got a value", value);
1497             assertTrue("Got correct type", (value instanceof Float));
1498             assertEquals("Got correct value",
1499                     ((Float) value).floatValue(),
1500                     bean.getNested().getFloatProperty(),
1501                     (float) 0.005);
1502         } catch (final IllegalAccessException e) {
1503             fail("IllegalAccessException");
1504         } catch (final IllegalArgumentException e) {
1505             fail("IllegalArgumentException");
1506         } catch (final InvocationTargetException e) {
1507             fail("InvocationTargetException");
1508         } catch (final NoSuchMethodException e) {
1509             fail("NoSuchMethodException");
1510         }
1511 
1512     }
1513 
1514 
1515     /**
1516      * Test getNestedProperty on an int property.
1517      */
1518     public void testGetNestedInt() {
1519 
1520         try {
1521             final Object value =
1522                     PropertyUtils.getNestedProperty
1523                     (bean, "nested.intProperty");
1524             assertNotNull("Got a value", value);
1525             assertTrue("Got correct type", (value instanceof Integer));
1526             assertEquals("Got correct value",
1527                     ((Integer) value).intValue(),
1528                     bean.getNested().getIntProperty());
1529         } catch (final IllegalAccessException e) {
1530             fail("IllegalAccessException");
1531         } catch (final IllegalArgumentException e) {
1532             fail("IllegalArgumentException");
1533         } catch (final InvocationTargetException e) {
1534             fail("InvocationTargetException");
1535         } catch (final NoSuchMethodException e) {
1536             fail("NoSuchMethodException");
1537         }
1538 
1539     }
1540 
1541 
1542     /**
1543      * Test getNestedProperty on a long property.
1544      */
1545     public void testGetNestedLong() {
1546 
1547         try {
1548             final Object value =
1549                     PropertyUtils.getNestedProperty
1550                     (bean, "nested.longProperty");
1551             assertNotNull("Got a value", value);
1552             assertTrue("Got correct type", (value instanceof Long));
1553             assertEquals("Got correct value",
1554                     ((Long) value).longValue(),
1555                     bean.getNested().getLongProperty());
1556         } catch (final IllegalAccessException e) {
1557             fail("IllegalAccessException");
1558         } catch (final IllegalArgumentException e) {
1559             fail("IllegalArgumentException");
1560         } catch (final InvocationTargetException e) {
1561             fail("InvocationTargetException");
1562         } catch (final NoSuchMethodException e) {
1563             fail("NoSuchMethodException");
1564         }
1565 
1566     }
1567 
1568 
1569     /**
1570      * Test getNestedProperty on a read-only String property.
1571      */
1572     public void testGetNestedReadOnly() {
1573 
1574         try {
1575             final Object value =
1576                     PropertyUtils.getNestedProperty
1577                     (bean, "nested.readOnlyProperty");
1578             assertNotNull("Got a value", value);
1579             assertTrue("Got correct type", (value instanceof String));
1580             assertEquals("Got correct value",
1581                     (String) value,
1582                     bean.getReadOnlyProperty());
1583         } catch (final IllegalAccessException e) {
1584             fail("IllegalAccessException");
1585         } catch (final IllegalArgumentException e) {
1586             fail("IllegalArgumentException");
1587         } catch (final InvocationTargetException e) {
1588             fail("InvocationTargetException");
1589         } catch (final NoSuchMethodException e) {
1590             fail("NoSuchMethodException");
1591         }
1592 
1593     }
1594 
1595 
1596     /**
1597      * Test getNestedProperty on a short property.
1598      */
1599     public void testGetNestedShort() {
1600 
1601         try {
1602             final Object value =
1603                     PropertyUtils.getNestedProperty
1604                     (bean, "nested.shortProperty");
1605             assertNotNull("Got a value", value);
1606             assertTrue("Got correct type", (value instanceof Short));
1607             assertEquals("Got correct value",
1608                     ((Short) value).shortValue(),
1609                     bean.getNested().getShortProperty());
1610         } catch (final IllegalAccessException e) {
1611             fail("IllegalAccessException");
1612         } catch (final IllegalArgumentException e) {
1613             fail("IllegalArgumentException");
1614         } catch (final InvocationTargetException e) {
1615             fail("InvocationTargetException");
1616         } catch (final NoSuchMethodException e) {
1617             fail("NoSuchMethodException");
1618         }
1619 
1620     }
1621 
1622 
1623     /**
1624      * Test getNestedProperty on a String property.
1625      */
1626     public void testGetNestedString() {
1627 
1628         try {
1629             final Object value =
1630                     PropertyUtils.getNestedProperty
1631                     (bean, "nested.stringProperty");
1632             assertNotNull("Got a value", value);
1633             assertTrue("Got correct type", (value instanceof String));
1634             assertEquals("Got correct value",
1635                     ((String) value),
1636                     bean.getNested().getStringProperty());
1637         } catch (final IllegalAccessException e) {
1638             fail("IllegalAccessException");
1639         } catch (final IllegalArgumentException e) {
1640             fail("IllegalArgumentException");
1641         } catch (final InvocationTargetException e) {
1642             fail("InvocationTargetException");
1643         } catch (final NoSuchMethodException e) {
1644             fail("NoSuchMethodException");
1645         }
1646 
1647     }
1648 
1649 
1650     /**
1651      * Negative test getNestedProperty on an unknown property.
1652      */
1653     public void testGetNestedUnknown() {
1654 
1655         try {
1656             PropertyUtils.getNestedProperty(bean, "nested.unknown");
1657             fail("Should have thrown NoSuchMethodException");
1658         } catch (final IllegalAccessException e) {
1659             fail("IllegalAccessException");
1660         } catch (final IllegalArgumentException e) {
1661             fail("IllegalArgumentException");
1662         } catch (final InvocationTargetException e) {
1663             fail("InvocationTargetException");
1664         } catch (final NoSuchMethodException e) {
1665             // Correct result for this test
1666         }
1667 
1668     }
1669 
1670     /**
1671      * When a bean has a null property which is reference by the standard access language,
1672      * this should throw a NestedNullException.
1673      */
1674     public void testThrowNestedNull() throws Exception {
1675         final NestedTestBean nestedBean = new NestedTestBean("base");
1676         // don't init!
1677 
1678         try {
1679             PropertyUtils.getProperty(
1680                                 nestedBean,
1681                                 "simpleBeanProperty.indexedProperty[0]");
1682             fail("NestedNullException not thrown");
1683         } catch (final NestedNullException e) {
1684             // that's what we wanted!
1685         }
1686     }
1687 
1688     /**
1689      * Test getNestedProperty on a write-only String property.
1690      */
1691     public void testGetNestedWriteOnly() {
1692 
1693         try {
1694             PropertyUtils.getNestedProperty(bean, "writeOnlyProperty");
1695             fail("Should have thrown NoSuchMethodException");
1696         } catch (final IllegalAccessException e) {
1697             fail("IllegalAccessException");
1698         } catch (final IllegalArgumentException e) {
1699             fail("IllegalArgumentException");
1700         } catch (final InvocationTargetException e) {
1701             fail("InvocationTargetException");
1702         } catch (final NoSuchMethodException e) {
1703             // Correct result for this test
1704         }
1705 
1706     }
1707 
1708 
1709     /**
1710      * Test getPropertyType() on all kinds of properties.
1711      */
1712     public void testGetPropertyType() {
1713 
1714         Class<?> clazz = null;
1715         final int intArray[] = new int[0];
1716         final String stringArray[] = new String[0];
1717 
1718         try {
1719 
1720             // Scalar and Indexed Properties
1721             clazz = PropertyUtils.getPropertyType(bean, "booleanProperty");
1722             assertEquals("booleanProperty type", Boolean.TYPE, clazz);
1723             clazz = PropertyUtils.getPropertyType(bean, "booleanSecond");
1724             assertEquals("booleanSecond type", Boolean.TYPE, clazz);
1725             clazz = PropertyUtils.getPropertyType(bean, "doubleProperty");
1726             assertEquals("doubleProperty type", Double.TYPE, clazz);
1727             clazz = PropertyUtils.getPropertyType(bean, "dupProperty");
1728             assertEquals("dupProperty type", String.class, clazz);
1729             clazz = PropertyUtils.getPropertyType(bean, "floatProperty");
1730             assertEquals("floatProperty type", Float.TYPE, clazz);
1731             clazz = PropertyUtils.getPropertyType(bean, "intArray");
1732             assertEquals("intArray type", intArray.getClass(), clazz);
1733             clazz = PropertyUtils.getPropertyType(bean, "intIndexed");
1734             assertEquals("intIndexed type", Integer.TYPE, clazz);
1735             clazz = PropertyUtils.getPropertyType(bean, "intProperty");
1736             assertEquals("intProperty type", Integer.TYPE, clazz);
1737             clazz = PropertyUtils.getPropertyType(bean, "listIndexed");
1738             assertEquals("listIndexed type", List.class, clazz);
1739             clazz = PropertyUtils.getPropertyType(bean, "longProperty");
1740             assertEquals("longProperty type", Long.TYPE, clazz);
1741             clazz = PropertyUtils.getPropertyType(bean, "mappedProperty");
1742             assertEquals("mappedProperty type", String.class, clazz);
1743             clazz = PropertyUtils.getPropertyType(bean, "mappedIntProperty");
1744             assertEquals("mappedIntProperty type", Integer.TYPE, clazz);
1745             clazz = PropertyUtils.getPropertyType(bean, "readOnlyProperty");
1746             assertEquals("readOnlyProperty type", String.class, clazz);
1747             clazz = PropertyUtils.getPropertyType(bean, "shortProperty");
1748             assertEquals("shortProperty type", Short.TYPE, clazz);
1749             clazz = PropertyUtils.getPropertyType(bean, "stringArray");
1750             assertEquals("stringArray type", stringArray.getClass(), clazz);
1751             clazz = PropertyUtils.getPropertyType(bean, "stringIndexed");
1752             assertEquals("stringIndexed type", String.class, clazz);
1753             clazz = PropertyUtils.getPropertyType(bean, "stringProperty");
1754             assertEquals("stringProperty type", String.class, clazz);
1755             clazz = PropertyUtils.getPropertyType(bean, "writeOnlyProperty");
1756             assertEquals("writeOnlyProperty type", String.class, clazz);
1757 
1758             // Nested Properties
1759             clazz = PropertyUtils.getPropertyType(bean, "nested.booleanProperty");
1760             assertEquals("booleanProperty type", Boolean.TYPE, clazz);
1761             clazz = PropertyUtils.getPropertyType(bean, "nested.booleanSecond");
1762             assertEquals("booleanSecond type", Boolean.TYPE, clazz);
1763             clazz = PropertyUtils.getPropertyType(bean, "nested.doubleProperty");
1764             assertEquals("doubleProperty type", Double.TYPE, clazz);
1765             clazz = PropertyUtils.getPropertyType(bean, "nested.dupProperty");
1766             assertEquals("dupProperty type", String.class, clazz);
1767             clazz = PropertyUtils.getPropertyType(bean, "nested.floatProperty");
1768             assertEquals("floatProperty type", Float.TYPE, clazz);
1769             clazz = PropertyUtils.getPropertyType(bean, "nested.intArray");
1770             assertEquals("intArray type", intArray.getClass(), clazz);
1771             clazz = PropertyUtils.getPropertyType(bean, "nested.intIndexed");
1772             assertEquals("intIndexed type", Integer.TYPE, clazz);
1773             clazz = PropertyUtils.getPropertyType(bean, "nested.intProperty");
1774             assertEquals("intProperty type", Integer.TYPE, clazz);
1775             clazz = PropertyUtils.getPropertyType(bean, "nested.listIndexed");
1776             assertEquals("listIndexed type", List.class, clazz);
1777             clazz = PropertyUtils.getPropertyType(bean, "nested.longProperty");
1778             assertEquals("longProperty type", Long.TYPE, clazz);
1779             clazz = PropertyUtils.getPropertyType(bean, "nested.mappedProperty");
1780             assertEquals("mappedProperty type", String.class, clazz);
1781             clazz = PropertyUtils.getPropertyType(bean, "nested.mappedIntProperty");
1782             assertEquals("mappedIntProperty type", Integer.TYPE, clazz);
1783             clazz = PropertyUtils.getPropertyType(bean, "nested.readOnlyProperty");
1784             assertEquals("readOnlyProperty type", String.class, clazz);
1785             clazz = PropertyUtils.getPropertyType(bean, "nested.shortProperty");
1786             assertEquals("shortProperty type", Short.TYPE, clazz);
1787             clazz = PropertyUtils.getPropertyType(bean, "nested.stringArray");
1788             assertEquals("stringArray type", stringArray.getClass(), clazz);
1789             clazz = PropertyUtils.getPropertyType(bean, "nested.stringIndexed");
1790             assertEquals("stringIndexed type", String.class, clazz);
1791             clazz = PropertyUtils.getPropertyType(bean, "nested.stringProperty");
1792             assertEquals("stringProperty type", String.class, clazz);
1793             clazz = PropertyUtils.getPropertyType(bean, "nested.writeOnlyProperty");
1794             assertEquals("writeOnlyProperty type", String.class, clazz);
1795 
1796             // Nested DynaBean
1797             clazz = PropertyUtils.getPropertyType(bean, "nestedDynaBean");
1798             assertEquals("nestedDynaBean type", DynaBean.class, clazz);
1799             clazz = PropertyUtils.getPropertyType(bean, "nestedDynaBean.stringProperty");
1800             assertEquals("nestedDynaBean.stringProperty type", String.class, clazz);
1801             clazz = PropertyUtils.getPropertyType(bean, "nestedDynaBean.nestedBean");
1802             assertEquals("nestedDynaBean.nestedBean type", TestBean.class, clazz);
1803             clazz = PropertyUtils.getPropertyType(bean, "nestedDynaBean.nestedBean.nestedDynaBean");
1804             assertEquals("nestedDynaBean.nestedBean.nestedDynaBean type", DynaBean.class, clazz);
1805             clazz = PropertyUtils.getPropertyType(bean, "nestedDynaBean.nestedBean.nestedDynaBean.stringProperty");
1806             assertEquals("nestedDynaBean.nestedBean.nestedDynaBean.stringPropert type", String.class, clazz);
1807 
1808             // test Null
1809             clazz = PropertyUtils.getPropertyType(bean, "nestedDynaBean.nullDynaBean");
1810             assertEquals("nestedDynaBean.nullDynaBean type", DynaBean.class, clazz);
1811             try {
1812                 clazz = PropertyUtils.getPropertyType(bean, "nestedDynaBean.nullDynaBean.foo");
1813                 fail("Expected NestedNullException for nestedDynaBean.nullDynaBean.foo");
1814             } catch (final NestedNullException e) {
1815                 // expected
1816             }
1817 
1818         } catch (final Exception e) {
1819             fail("Exception: " + e.getMessage());
1820         }
1821 
1822     }
1823 
1824 
1825     /**
1826      * Test accessing a public sub-bean of a package scope bean
1827      */
1828     public void testGetPublicSubBean_of_PackageBean() {
1829 
1830         final PublicSubBean bean = new PublicSubBean();
1831         bean.setFoo("foo-start");
1832         bean.setBar("bar-start");
1833         Object result = null;
1834 
1835         // Get Foo
1836         try {
1837             result = PropertyUtils.getProperty(bean, "foo");
1838         } catch (final Throwable t) {
1839             fail("getProperty(foo) threw " + t);
1840         }
1841         assertEquals("foo property", "foo-start", result);
1842 
1843         // Get Bar
1844         try {
1845             result = PropertyUtils.getProperty(bean, "bar");
1846         } catch (final Throwable t) {
1847             fail("getProperty(bar) threw " + t);
1848         }
1849         assertEquals("bar property", "bar-start", result);
1850     }
1851 
1852 
1853     /**
1854      * Test getting accessible property reader methods for a specified
1855      * list of properties of our standard test bean.
1856      */
1857     public void testGetReadMethodBasic() {
1858 
1859         testGetReadMethod(bean, properties, TEST_BEAN_CLASS);
1860 
1861     }
1862 
1863 
1864     /**
1865      * Test getting accessible property reader methods for a specified
1866      * list of properties of a package private subclass of our standard
1867      * test bean.
1868      */
1869     public void testGetReadMethodPackageSubclass() {
1870 
1871         testGetReadMethod(beanPackageSubclass, properties, TEST_BEAN_CLASS);
1872 
1873     }
1874 
1875 
1876     /**
1877      * Test getting accessible property reader methods for a specified
1878      * list of properties that are declared either directly or via
1879      * implemented interfaces.
1880      */
1881     public void testGetReadMethodPublicInterface() {
1882 
1883         // Properties "bar" and "baz" are visible via implemented interfaces
1884         // (one direct and one indirect)
1885         testGetReadMethod(beanPrivate,
1886                 new String[]{ "bar" },
1887                 PRIVATE_DIRECT_CLASS);
1888         testGetReadMethod(beanPrivate,
1889                 new String[]{ "baz" },
1890                 PRIVATE_INDIRECT_CLASS);
1891 
1892         // Properties "bar" and "baz" are visible via implemented interfaces
1893         // (one direct and one indirect).  The interface is implemented in
1894         // a superclass
1895         testGetReadMethod(beanPrivateSubclass,
1896                 new String[]{ "bar" },
1897                 PRIVATE_DIRECT_CLASS);
1898         testGetReadMethod(beanPrivateSubclass,
1899                 new String[]{ "baz" },
1900                 PRIVATE_INDIRECT_CLASS);
1901 
1902         // Property "foo" is not accessible because the underlying
1903         // class has package scope
1904         final PropertyDescriptor pd[] =
1905                 PropertyUtils.getPropertyDescriptors(beanPrivate);
1906         int n = -1;
1907         for (int i = 0; i < pd.length; i++) {
1908             if ("foo".equals(pd[i].getName())) {
1909                 n = i;
1910                 break;
1911             }
1912         }
1913         assertTrue("Found foo descriptor", n >= 0);
1914         final Method reader = pd[n].getReadMethod();
1915         assertNotNull("Found foo read method", reader);
1916         try {
1917             reader.invoke(beanPrivate, (Object[]) new Class<?>[0]);
1918             fail("Foo reader did throw IllegalAccessException");
1919         } catch (final IllegalAccessException e) {
1920             // Expected result for this test
1921         } catch (final Throwable t) {
1922             fail("Invoke foo reader: " + t);
1923         }
1924 
1925     }
1926 
1927 
1928     /**
1929      * Test getting accessible property reader methods for a specified
1930      * list of properties of a public subclass of our standard test bean.
1931      */
1932     public void testGetReadMethodPublicSubclass() {
1933 
1934         testGetReadMethod(beanPublicSubclass, properties, TEST_BEAN_CLASS);
1935 
1936     }
1937 
1938 
1939     /**
1940      * Corner cases on getSimpleProperty invalid arguments.
1941      */
1942     public void testGetSimpleArguments() {
1943 
1944         try {
1945             PropertyUtils.getSimpleProperty(null, "stringProperty");
1946             fail("Should throw IllegalArgumentException 1");
1947         } catch (final IllegalArgumentException e) {
1948             // Expected response
1949         } catch (final Throwable t) {
1950             fail("Threw " + t + " instead of IllegalArgumentException 1");
1951         }
1952 
1953         try {
1954             PropertyUtils.getSimpleProperty(bean, null);
1955             fail("Should throw IllegalArgumentException 2");
1956         } catch (final IllegalArgumentException e) {
1957             // Expected response
1958         } catch (final Throwable t) {
1959             fail("Threw " + t + " instead of IllegalArgumentException 2");
1960         }
1961 
1962     }
1963 
1964 
1965     /**
1966      * Test getSimpleProperty on a boolean property.
1967      */
1968     public void testGetSimpleBoolean() {
1969 
1970         try {
1971             final Object value =
1972                     PropertyUtils.getSimpleProperty(bean,
1973                             "booleanProperty");
1974             assertNotNull("Got a value", value);
1975             assertTrue("Got correct type", (value instanceof Boolean));
1976             assertTrue("Got correct value",
1977                     ((Boolean) value).booleanValue() ==
1978                     bean.getBooleanProperty());
1979         } catch (final IllegalAccessException e) {
1980             fail("IllegalAccessException");
1981         } catch (final IllegalArgumentException e) {
1982             fail("IllegalArgumentException");
1983         } catch (final InvocationTargetException e) {
1984             fail("InvocationTargetException");
1985         } catch (final NoSuchMethodException e) {
1986             fail("NoSuchMethodException");
1987         }
1988 
1989     }
1990 
1991 
1992     /**
1993      * Test getSimpleProperty on a double property.
1994      */
1995     public void testGetSimpleDouble() {
1996 
1997         try {
1998             final Object value =
1999                     PropertyUtils.getSimpleProperty(bean,
2000                             "doubleProperty");
2001             assertNotNull("Got a value", value);
2002             assertTrue("Got correct type", (value instanceof Double));
2003             assertEquals("Got correct value",
2004                     ((Double) value).doubleValue(),
2005                     bean.getDoubleProperty(), 0.005);
2006         } catch (final IllegalAccessException e) {
2007             fail("IllegalAccessException");
2008         } catch (final IllegalArgumentException e) {
2009             fail("IllegalArgumentException");
2010         } catch (final InvocationTargetException e) {
2011             fail("InvocationTargetException");
2012         } catch (final NoSuchMethodException e) {
2013             fail("NoSuchMethodException");
2014         }
2015 
2016     }
2017 
2018 
2019     /**
2020      * Test getSimpleProperty on a float property.
2021      */
2022     public void testGetSimpleFloat() {
2023 
2024         try {
2025             final Object value =
2026                     PropertyUtils.getSimpleProperty(bean,
2027                             "floatProperty");
2028             assertNotNull("Got a value", value);
2029             assertTrue("Got correct type", (value instanceof Float));
2030             assertEquals("Got correct value",
2031                     ((Float) value).floatValue(),
2032                     bean.getFloatProperty(),
2033                     (float) 0.005);
2034         } catch (final IllegalAccessException e) {
2035             fail("IllegalAccessException");
2036         } catch (final IllegalArgumentException e) {
2037             fail("IllegalArgumentException");
2038         } catch (final InvocationTargetException e) {
2039             fail("InvocationTargetException");
2040         } catch (final NoSuchMethodException e) {
2041             fail("NoSuchMethodException");
2042         }
2043 
2044     }
2045 
2046 
2047     /**
2048      * Negative test getSimpleProperty on an indexed property.
2049      */
2050     public void testGetSimpleIndexed() {
2051 
2052         try {
2053             PropertyUtils.getSimpleProperty(bean,
2054                     "intIndexed[0]");
2055             fail("Should have thrown IllegalArgumentException");
2056         } catch (final IllegalAccessException e) {
2057             fail("IllegalAccessException");
2058         } catch (final IllegalArgumentException e) {
2059             // Correct result for this test
2060         } catch (final InvocationTargetException e) {
2061             fail("InvocationTargetException");
2062         } catch (final NoSuchMethodException e) {
2063             fail("NoSuchMethodException");
2064         }
2065 
2066     }
2067 
2068 
2069     /**
2070      * Test getSimpleProperty on an int property.
2071      */
2072     public void testGetSimpleInt() {
2073 
2074         try {
2075             final Object value =
2076                     PropertyUtils.getSimpleProperty(bean,
2077                             "intProperty");
2078             assertNotNull("Got a value", value);
2079             assertTrue("Got correct type", (value instanceof Integer));
2080             assertEquals("Got correct value",
2081                     ((Integer) value).intValue(),
2082                     bean.getIntProperty());
2083         } catch (final IllegalAccessException e) {
2084             fail("IllegalAccessException");
2085         } catch (final IllegalArgumentException e) {
2086             fail("IllegalArgumentException");
2087         } catch (final InvocationTargetException e) {
2088             fail("InvocationTargetException");
2089         } catch (final NoSuchMethodException e) {
2090             fail("NoSuchMethodException");
2091         }
2092 
2093     }
2094 
2095 
2096     /**
2097      * Test getSimpleProperty on a long property.
2098      */
2099     public void testGetSimpleLong() {
2100 
2101         try {
2102             final Object value =
2103                     PropertyUtils.getSimpleProperty(bean,
2104                             "longProperty");
2105             assertNotNull("Got a value", value);
2106             assertTrue("Got correct type", (value instanceof Long));
2107             assertEquals("Got correct value",
2108                     ((Long) value).longValue(),
2109                     bean.getLongProperty());
2110         } catch (final IllegalAccessException e) {
2111             fail("IllegalAccessException");
2112         } catch (final IllegalArgumentException e) {
2113             fail("IllegalArgumentException");
2114         } catch (final InvocationTargetException e) {
2115             fail("InvocationTargetException");
2116         } catch (final NoSuchMethodException e) {
2117             fail("NoSuchMethodException");
2118         }
2119 
2120     }
2121 
2122 
2123     /**
2124      * Negative test getSimpleProperty on a nested property.
2125      */
2126     public void testGetSimpleNested() {
2127 
2128         try {
2129             PropertyUtils.getSimpleProperty(bean,
2130                     "nested.stringProperty");
2131             fail("Should have thrown IllegaArgumentException");
2132         } catch (final IllegalAccessException e) {
2133             fail("IllegalAccessException");
2134         } catch (final IllegalArgumentException e) {
2135             // Correct result for this test
2136         } catch (final InvocationTargetException e) {
2137             fail("InvocationTargetException");
2138         } catch (final NoSuchMethodException e) {
2139             fail("NoSuchMethodException");
2140         }
2141 
2142     }
2143 
2144 
2145     /**
2146      * Test getSimpleProperty on a read-only String property.
2147      */
2148     public void testGetSimpleReadOnly() {
2149 
2150         try {
2151             final Object value =
2152                     PropertyUtils.getSimpleProperty(bean,
2153                             "readOnlyProperty");
2154             assertNotNull("Got a value", value);
2155             assertTrue("Got correct type", (value instanceof String));
2156             assertEquals("Got correct value",
2157                     (String) value,
2158                     bean.getReadOnlyProperty());
2159         } catch (final IllegalAccessException e) {
2160             fail("IllegalAccessException");
2161         } catch (final IllegalArgumentException e) {
2162             fail("IllegalArgumentException");
2163         } catch (final InvocationTargetException e) {
2164             fail("InvocationTargetException");
2165         } catch (final NoSuchMethodException e) {
2166             fail("NoSuchMethodException");
2167         }
2168 
2169     }
2170 
2171 
2172     /**
2173      * Test getSimpleProperty on a short property.
2174      */
2175     public void testGetSimpleShort() {
2176 
2177         try {
2178             final Object value =
2179                     PropertyUtils.getSimpleProperty(bean,
2180                             "shortProperty");
2181             assertNotNull("Got a value", value);
2182             assertTrue("Got correct type", (value instanceof Short));
2183             assertEquals("Got correct value",
2184                     ((Short) value).shortValue(),
2185                     bean.getShortProperty());
2186         } catch (final IllegalAccessException e) {
2187             fail("IllegalAccessException");
2188         } catch (final IllegalArgumentException e) {
2189             fail("IllegalArgumentException");
2190         } catch (final InvocationTargetException e) {
2191             fail("InvocationTargetException");
2192         } catch (final NoSuchMethodException e) {
2193             fail("NoSuchMethodException");
2194         }
2195 
2196     }
2197 
2198 
2199     /**
2200      * Test getSimpleProperty on a String property.
2201      */
2202     public void testGetSimpleString() {
2203 
2204         try {
2205             final Object value =
2206                     PropertyUtils.getSimpleProperty(bean,
2207                             "stringProperty");
2208             assertNotNull("Got a value", value);
2209             assertTrue("Got correct type", (value instanceof String));
2210             assertEquals("Got correct value",
2211                     (String) value,
2212                     bean.getStringProperty());
2213         } catch (final IllegalAccessException e) {
2214             fail("IllegalAccessException");
2215         } catch (final IllegalArgumentException e) {
2216             fail("IllegalArgumentException");
2217         } catch (final InvocationTargetException e) {
2218             fail("InvocationTargetException");
2219         } catch (final NoSuchMethodException e) {
2220             fail("NoSuchMethodException");
2221         }
2222 
2223     }
2224 
2225 
2226     /**
2227      * Negative test getSimpleProperty on an unknown property.
2228      */
2229     public void testGetSimpleUnknown() {
2230 
2231         try {
2232             PropertyUtils.getSimpleProperty(bean, "unknown");
2233             fail("Should have thrown NoSuchMethodException");
2234         } catch (final IllegalAccessException e) {
2235             fail("IllegalAccessException");
2236         } catch (final IllegalArgumentException e) {
2237             fail("IllegalArgumentException");
2238         } catch (final InvocationTargetException e) {
2239             fail("InvocationTargetException");
2240         } catch (final NoSuchMethodException e) {
2241             // Correct result for this test
2242             assertEquals("Unknown property 'unknown' on class '" +
2243                          bean.getClass() + "'", e.getMessage() );
2244         }
2245 
2246     }
2247 
2248 
2249     /**
2250      * Test getSimpleProperty on a write-only String property.
2251      */
2252     public void testGetSimpleWriteOnly() {
2253 
2254         try {
2255             PropertyUtils.getSimpleProperty(bean, "writeOnlyProperty");
2256             fail("Should have thrown NoSuchMethodException");
2257         } catch (final IllegalAccessException e) {
2258             fail("IllegalAccessException");
2259         } catch (final IllegalArgumentException e) {
2260             fail("IllegalArgumentException");
2261         } catch (final InvocationTargetException e) {
2262             fail("InvocationTargetException");
2263         } catch (final NoSuchMethodException e) {
2264             // Correct result for this test
2265             assertEquals("Property 'writeOnlyProperty' has no getter method in class '" +
2266                          bean.getClass() + "'", e.getMessage() );
2267         }
2268 
2269     }
2270 
2271 
2272     /**
2273      * Test getting accessible property writer methods for a specified
2274      * list of properties of our standard test bean.
2275      */
2276     public void testGetWriteMethodBasic() {
2277 
2278         testGetWriteMethod(bean, properties, TEST_BEAN_CLASS);
2279 
2280     }
2281 
2282 
2283     /**
2284      * Test getting accessible property writer methods for a specified
2285      * list of properties of a package private subclass of our standard
2286      * test bean.
2287      */
2288     public void testGetWriteMethodPackageSubclass() {
2289 
2290         testGetWriteMethod(beanPackageSubclass, properties, TEST_BEAN_CLASS);
2291 
2292     }
2293 
2294 
2295     /**
2296      * Test getting accessible property writer methods for a specified
2297      * list of properties of a public subclass of our standard test bean.
2298      */
2299     public void testGetWriteMethodPublicSubclass() {
2300 
2301         testGetWriteMethod(beanPublicSubclass, properties, TEST_BEAN_CLASS);
2302 
2303     }
2304 
2305     /**
2306      * Test isReadable() method.
2307      */
2308     public void testIsReadable() {
2309         String property = null;
2310         try {
2311             property = "stringProperty";
2312             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2313         } catch (final Throwable t) {
2314             fail("Property " + property +" isReadable Threw exception: " + t);
2315         }
2316         try {
2317             property = "stringIndexed";
2318             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2319         } catch (final Throwable t) {
2320             fail("Property " + property +" isReadable Threw exception: " + t);
2321         }
2322         try {
2323             property = "mappedProperty";
2324             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2325         } catch (final Throwable t) {
2326             fail("Property " + property +" isReadable Threw exception: " + t);
2327         }
2328 
2329         try {
2330             property = "nestedDynaBean";
2331             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2332         } catch (final Throwable t) {
2333             fail("Property " + property +" isReadable Threw exception: " + t);
2334         }
2335 
2336         try {
2337             property = "nestedDynaBean.stringProperty";
2338             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2339         } catch (final Throwable t) {
2340             fail("Property " + property +" isReadable Threw exception: " + t);
2341         }
2342 
2343         try {
2344             property = "nestedDynaBean.nestedBean";
2345             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2346         } catch (final Throwable t) {
2347             fail("Property " + property +" isReadable Threw exception: " + t);
2348         }
2349 
2350         try {
2351             property = "nestedDynaBean.nestedBean.nestedDynaBean";
2352             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2353         } catch (final Throwable t) {
2354             fail("Property " + property +" isReadable Threw exception: " + t);
2355         }
2356 
2357         try {
2358             property = "nestedDynaBean.nestedBean.nestedDynaBean.stringProperty";
2359             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2360         } catch (final Throwable t) {
2361             fail("Property " + property +" isReadable Threw exception: " + t);
2362         }
2363 
2364         try {
2365             property = "nestedDynaBean.nullDynaBean";
2366             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2367         } catch (final Throwable t) {
2368             fail("Property " + property +" isReadable Threw exception: " + t);
2369         }
2370 
2371         try {
2372             property = "nestedDynaBean.nullDynaBean.foo";
2373             assertTrue("Property " + property +" isReadable expeced TRUE", PropertyUtils.isReadable(bean, property));
2374             fail("Property " + property +" isReadable expected NestedNullException");
2375         } catch (final NestedNullException e) {
2376             // expected result
2377         } catch (final Throwable t) {
2378             fail("Property " + property +" isReadable Threw exception: " + t);
2379         }
2380     }
2381 
2382     /**
2383      * Test isWriteable() method.
2384      */
2385     public void testIsWriteable() {
2386         String property = null;
2387         try {
2388             property = "stringProperty";
2389             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2390         } catch (final Throwable t) {
2391             fail("Property " + property +" isWriteable Threw exception: " + t);
2392         }
2393         try {
2394             property = "stringIndexed";
2395             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2396         } catch (final Throwable t) {
2397             fail("Property " + property +" isWriteable Threw exception: " + t);
2398         }
2399         try {
2400             property = "mappedProperty";
2401             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2402         } catch (final Throwable t) {
2403             fail("Property " + property +" isWriteable Threw exception: " + t);
2404         }
2405 
2406         try {
2407             property = "nestedDynaBean";
2408             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2409         } catch (final Throwable t) {
2410             fail("Property " + property +" isWriteable Threw exception: " + t);
2411         }
2412 
2413         try {
2414             property = "nestedDynaBean.stringProperty";
2415             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2416         } catch (final Throwable t) {
2417             t.printStackTrace();
2418             fail("Property " + property +" isWriteable Threw exception: " + t);
2419         }
2420 
2421         try {
2422             property = "nestedDynaBean.nestedBean";
2423             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2424         } catch (final Throwable t) {
2425             fail("Property " + property +" isWriteable Threw exception: " + t);
2426         }
2427 
2428         try {
2429             property = "nestedDynaBean.nestedBean.nestedDynaBean";
2430             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2431         } catch (final Throwable t) {
2432             fail("Property " + property +" isWriteable Threw exception: " + t);
2433         }
2434 
2435         try {
2436             property = "nestedDynaBean.nestedBean.nestedDynaBean.stringProperty";
2437             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2438         } catch (final Throwable t) {
2439             fail("Property " + property +" isWriteable Threw exception: " + t);
2440         }
2441 
2442         try {
2443             property = "nestedDynaBean.nullDynaBean";
2444             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2445         } catch (final Throwable t) {
2446             fail("Property " + property +" isWriteable Threw exception: " + t);
2447         }
2448 
2449         try {
2450             property = "nestedDynaBean.nullDynaBean.foo";
2451             assertTrue("Property " + property +" isWriteable expeced TRUE", PropertyUtils.isWriteable(bean, property));
2452             fail("Property " + property +" isWriteable expected NestedNullException");
2453         } catch (final NestedNullException e) {
2454             // expected result
2455         } catch (final Throwable t) {
2456             fail("Property " + property +" isWriteable Threw exception: " + t);
2457         }
2458     }
2459 
2460 
2461     /**
2462      * Test the mappedPropertyType of MappedPropertyDescriptor.
2463      */
2464     public void testMappedPropertyType() throws Exception {
2465 
2466         MappedPropertyDescriptor desc;
2467 
2468         // Check a String property
2469         desc = (MappedPropertyDescriptor)
2470                 PropertyUtils.getPropertyDescriptor(bean,
2471                         "mappedProperty");
2472         assertEquals(String.class, desc.getMappedPropertyType());
2473 
2474         // Check an int property
2475         desc = (MappedPropertyDescriptor)
2476                 PropertyUtils.getPropertyDescriptor(bean,
2477                         "mappedIntProperty");
2478         assertEquals(Integer.TYPE, desc.getMappedPropertyType());
2479 
2480     }
2481 
2482 
2483     /**
2484      * Corner cases on setIndexedProperty invalid arguments.
2485      */
2486     public void testSetIndexedArguments() {
2487 
2488         // Use explicit index argument
2489 
2490         try {
2491             PropertyUtils.setIndexedProperty(null, "intArray", 0,
2492                     new Integer(1));
2493             fail("Should throw IllegalArgumentException 1");
2494         } catch (final IllegalArgumentException e) {
2495             // Expected response
2496         } catch (final Throwable t) {
2497             fail("Threw " + t + " instead of IllegalArgumentException 1");
2498         }
2499 
2500         try {
2501             PropertyUtils.setIndexedProperty(bean, null, 0,
2502                     new Integer(1));
2503             fail("Should throw IllegalArgumentException 2");
2504         } catch (final IllegalArgumentException e) {
2505             // Expected response
2506         } catch (final Throwable t) {
2507             fail("Threw " + t + " instead of IllegalArgumentException 2");
2508         }
2509 
2510         // Use index expression
2511 
2512         try {
2513             PropertyUtils.setIndexedProperty(null,
2514                     "intArray[0]",
2515                     new Integer(1));
2516             fail("Should throw IllegalArgumentException 3");
2517         } catch (final IllegalArgumentException e) {
2518             // Expected response
2519         } catch (final Throwable t) {
2520             fail("Threw " + t + " instead of IllegalArgumentException 3");
2521         }
2522 
2523         try {
2524             PropertyUtils.setIndexedProperty(bean, "[0]",
2525                     new Integer(1));
2526             fail("Should throw NoSuchMethodException 4");
2527         } catch (final NoSuchMethodException e) {
2528             // Expected response
2529         } catch (final Throwable t) {
2530             fail("Threw " + t + " instead of NoSuchMethodException 4");
2531         }
2532 
2533         try {
2534             PropertyUtils.setIndexedProperty(bean, "intArray",
2535                     new Integer(1));
2536             fail("Should throw IllegalArgumentException 5");
2537         } catch (final IllegalArgumentException e) {
2538             // Expected response
2539         } catch (final Throwable t) {
2540             fail("Threw " + t + " instead of IllegalArgumentException 5");
2541         }
2542 
2543         // Use explicit index argument
2544 
2545         try {
2546             PropertyUtils.setIndexedProperty(null, "intIndexed", 0,
2547                     new Integer(1));
2548             fail("Should throw IllegalArgumentException 1");
2549         } catch (final IllegalArgumentException e) {
2550             // Expected response
2551         } catch (final Throwable t) {
2552             fail("Threw " + t + " instead of IllegalArgumentException 1");
2553         }
2554 
2555         try {
2556             PropertyUtils.setIndexedProperty(bean, null, 0,
2557                     new Integer(1));
2558             fail("Should throw IllegalArgumentException 2");
2559         } catch (final IllegalArgumentException e) {
2560             // Expected response
2561         } catch (final Throwable t) {
2562             fail("Threw " + t + " instead of IllegalArgumentException 2");
2563         }
2564 
2565         // Use index expression
2566 
2567         try {
2568             PropertyUtils.setIndexedProperty(null,
2569                     "intIndexed[0]",
2570                     new Integer(1));
2571             fail("Should throw IllegalArgumentException 3");
2572         } catch (final IllegalArgumentException e) {
2573             // Expected response
2574         } catch (final Throwable t) {
2575             fail("Threw " + t + " instead of IllegalArgumentException 3");
2576         }
2577 
2578         try {
2579             PropertyUtils.setIndexedProperty(bean, "[0]",
2580                     new Integer(1));
2581             fail("Should throw NoSuchMethodException 4");
2582         } catch (final NoSuchMethodException e) {
2583             // Expected response
2584         } catch (final Throwable t) {
2585             fail("Threw " + t + " instead of NoSuchMethodException 4");
2586         }
2587 
2588         try {
2589             PropertyUtils.setIndexedProperty(bean, "intIndexed",
2590                     new Integer(1));
2591             fail("Should throw IllegalArgumentException 5");
2592         } catch (final IllegalArgumentException e) {
2593             // Expected response
2594         } catch (final Throwable t) {
2595             fail("Threw " + t + " instead of IllegalArgumentException 5");
2596         }
2597 
2598     }
2599 
2600     /**
2601      * Test setting an indexed value out of a multi-dimensional array
2602      */
2603     public void testSetIndexedArray() {
2604         final String[] firstArray = new String[] {"FIRST-1", "FIRST-2", "FIRST-3"};
2605         final String[] secondArray = new String[] {"SECOND-1", "SECOND-2", "SECOND-3",  "SECOND-4"};
2606         final String[][] mainArray = {firstArray, secondArray};
2607         final TestBean bean = new TestBean(mainArray);
2608         assertEquals("BEFORE", "SECOND-3", bean.getString2dArray(1)[2]);
2609         try {
2610             PropertyUtils.setProperty(bean, "string2dArray[1][2]", "SECOND-3-UPDATED");
2611         } catch (final Throwable t) {
2612             fail("Threw " + t + "");
2613         }
2614         assertEquals("AFTER", "SECOND-3-UPDATED", bean.getString2dArray(1)[2]);
2615     }
2616 
2617     /**
2618      * Test setting an indexed value out of List of Lists
2619      */
2620     public void testSetIndexedList() {
2621         final String[] firstArray = new String[] {"FIRST-1", "FIRST-2", "FIRST-3"};
2622         final String[] secondArray = new String[] {"SECOND-1", "SECOND-2", "SECOND-3",  "SECOND-4"};
2623         final List<Object> mainList   = new ArrayList<Object>();
2624         mainList.add(Arrays.asList(firstArray));
2625         mainList.add(Arrays.asList(secondArray));
2626         final TestBean bean = new TestBean(mainList);
2627         assertEquals("BEFORE", "SECOND-4", ((List<?>)bean.getListIndexed().get(1)).get(3));
2628         try {
2629             PropertyUtils.setProperty(bean, "listIndexed[1][3]", "SECOND-4-UPDATED");
2630         } catch (final Throwable t) {
2631             fail("Threw " + t + "");
2632         }
2633         assertEquals("AFTER", "SECOND-4-UPDATED", ((List<?>)bean.getListIndexed().get(1)).get(3));
2634     }
2635 
2636     /**
2637      * Test setting a value out of a mapped Map
2638      */
2639     public void testSetIndexedMap() {
2640         final Map<String, Object> firstMap  = new HashMap<String, Object>();
2641         firstMap.put("FIRST-KEY-1", "FIRST-VALUE-1");
2642         firstMap.put("FIRST-KEY-2", "FIRST-VALUE-2");
2643         final Map<String, Object> secondMap  = new HashMap<String, Object>();
2644         secondMap.put("SECOND-KEY-1", "SECOND-VALUE-1");
2645         secondMap.put("SECOND-KEY-2", "SECOND-VALUE-2");
2646 
2647         final List<Object> mainList = new ArrayList<Object>();
2648         mainList.add(firstMap);
2649         mainList.add(secondMap);
2650         final TestBean bean = new TestBean(mainList);
2651 
2652         assertEquals("BEFORE",  null,              ((Map<?, ?>)bean.getListIndexed().get(0)).get("FIRST-NEW-KEY"));
2653         assertEquals("BEFORE",  "SECOND-VALUE-1",  ((Map<?, ?>)bean.getListIndexed().get(1)).get("SECOND-KEY-1"));
2654         try {
2655             PropertyUtils.setProperty(bean, "listIndexed[0](FIRST-NEW-KEY)", "FIRST-NEW-VALUE");
2656             PropertyUtils.setProperty(bean, "listIndexed[1](SECOND-KEY-1)",  "SECOND-VALUE-1-UPDATED");
2657         } catch (final Throwable t) {
2658             fail("Threw " + t + "");
2659         }
2660         assertEquals("BEFORE", "FIRST-NEW-VALUE",         ((Map<?, ?>)bean.getListIndexed().get(0)).get("FIRST-NEW-KEY"));
2661         assertEquals("AFTER",  "SECOND-VALUE-1-UPDATED",  ((Map<?, ?>)bean.getListIndexed().get(1)).get("SECOND-KEY-1"));
2662     }
2663 
2664 
2665     /**
2666      * Positive and negative tests on setIndexedProperty valid arguments.
2667      */
2668     public void testSetIndexedValues() {
2669 
2670         Object value = null;
2671 
2672         // Use explicit index argument
2673 
2674         try {
2675             PropertyUtils.setIndexedProperty(bean,
2676                     "dupProperty", 0,
2677                     "New 0");
2678             value =
2679                     PropertyUtils.getIndexedProperty(bean,
2680                             "dupProperty", 0);
2681             assertNotNull("Returned new value 0", value);
2682             assertTrue("Returned String new value 0",
2683                     value instanceof String);
2684             assertEquals("Returned correct new value 0", "New 0",
2685                     (String) value);
2686         } catch (final Throwable t) {
2687             fail("Threw " + t);
2688         }
2689 
2690         try {
2691             PropertyUtils.setIndexedProperty(bean,
2692                     "intArray", 0,
2693                     new Integer(1));
2694             value =
2695                     PropertyUtils.getIndexedProperty(bean,
2696                             "intArray", 0);
2697             assertNotNull("Returned new value 0", value);
2698             assertTrue("Returned Integer new value 0",
2699                     value instanceof Integer);
2700             assertEquals("Returned correct new value 0", 1,
2701                     ((Integer) value).intValue());
2702         } catch (final Throwable t) {
2703             fail("Threw " + t);
2704         }
2705 
2706         try {
2707             PropertyUtils.setIndexedProperty(bean,
2708                     "intIndexed", 1,
2709                     new Integer(11));
2710             value =
2711                     PropertyUtils.getIndexedProperty(bean,
2712                             "intIndexed", 1);
2713             assertNotNull("Returned new value 1", value);
2714             assertTrue("Returned Integer new value 1",
2715                     value instanceof Integer);
2716             assertEquals("Returned correct new value 1", 11,
2717                     ((Integer) value).intValue());
2718         } catch (final Throwable t) {
2719             fail("Threw " + t);
2720         }
2721 
2722         try {
2723             PropertyUtils.setIndexedProperty(bean,
2724                     "listIndexed", 2,
2725                     "New Value 2");
2726             value =
2727                     PropertyUtils.getIndexedProperty(bean,
2728                             "listIndexed", 2);
2729             assertNotNull("Returned new value 2", value);
2730             assertTrue("Returned String new value 2",
2731                     value instanceof String);
2732             assertEquals("Returned correct new value 2", "New Value 2",
2733                     (String) value);
2734         } catch (final Throwable t) {
2735             fail("Threw " + t);
2736         }
2737 
2738         try {
2739             PropertyUtils.setIndexedProperty(bean,
2740                     "stringArray", 2,
2741                     "New Value 2");
2742             value =
2743                     PropertyUtils.getIndexedProperty(bean,
2744                             "stringArray", 2);
2745             assertNotNull("Returned new value 2", value);
2746             assertTrue("Returned String new value 2",
2747                     value instanceof String);
2748             assertEquals("Returned correct new value 2", "New Value 2",
2749                     (String) value);
2750         } catch (final Throwable t) {
2751             fail("Threw " + t);
2752         }
2753 
2754         try {
2755             PropertyUtils.setIndexedProperty(bean,
2756                     "stringArray", 3,
2757                     "New Value 3");
2758             value =
2759                     PropertyUtils.getIndexedProperty(bean,
2760                             "stringArray", 3);
2761             assertNotNull("Returned new value 3", value);
2762             assertTrue("Returned String new value 3",
2763                     value instanceof String);
2764             assertEquals("Returned correct new value 3", "New Value 3",
2765                     (String) value);
2766         } catch (final Throwable t) {
2767             fail("Threw " + t);
2768         }
2769 
2770         // Use index expression
2771 
2772         try {
2773             PropertyUtils.setIndexedProperty(bean,
2774                     "dupProperty[4]",
2775                     "New 4");
2776             value =
2777                     PropertyUtils.getIndexedProperty(bean,
2778                             "dupProperty[4]");
2779             assertNotNull("Returned new value 4", value);
2780             assertTrue("Returned String new value 4",
2781                     value instanceof String);
2782             assertEquals("Returned correct new value 4", "New 4",
2783                          (String) value);
2784         } catch (final Throwable t) {
2785             fail("Threw " + t);
2786         }
2787 
2788         try {
2789             PropertyUtils.setIndexedProperty(bean,
2790                     "intArray[4]",
2791                     new Integer(1));
2792             value =
2793                     PropertyUtils.getIndexedProperty(bean,
2794                             "intArray[4]");
2795             assertNotNull("Returned new value 4", value);
2796             assertTrue("Returned Integer new value 4",
2797                     value instanceof Integer);
2798             assertEquals("Returned correct new value 4", 1,
2799                     ((Integer) value).intValue());
2800         } catch (final Throwable t) {
2801             fail("Threw " + t);
2802         }
2803 
2804         try {
2805             PropertyUtils.setIndexedProperty(bean,
2806                     "intIndexed[3]",
2807                     new Integer(11));
2808             value =
2809                     PropertyUtils.getIndexedProperty(bean,
2810                             "intIndexed[3]");
2811             assertNotNull("Returned new value 5", value);
2812             assertTrue("Returned Integer new value 5",
2813                     value instanceof Integer);
2814             assertEquals("Returned correct new value 5", 11,
2815                     ((Integer) value).intValue());
2816         } catch (final Throwable t) {
2817             fail("Threw " + t);
2818         }
2819 
2820         try {
2821             PropertyUtils.setIndexedProperty(bean,
2822                     "listIndexed[1]",
2823                     "New Value 2");
2824             value =
2825                     PropertyUtils.getIndexedProperty(bean,
2826                             "listIndexed[1]");
2827             assertNotNull("Returned new value 6", value);
2828             assertTrue("Returned String new value 6",
2829                     value instanceof String);
2830             assertEquals("Returned correct new value 6", "New Value 2",
2831                     (String) value);
2832         } catch (final Throwable t) {
2833             fail("Threw " + t);
2834         }
2835 
2836         try {
2837             PropertyUtils.setIndexedProperty(bean,
2838                     "stringArray[1]",
2839                     "New Value 2");
2840             value =
2841                     PropertyUtils.getIndexedProperty(bean,
2842                             "stringArray[2]");
2843             assertNotNull("Returned new value 6", value);
2844             assertTrue("Returned String new value 6",
2845                     value instanceof String);
2846             assertEquals("Returned correct new value 6", "New Value 2",
2847                     (String) value);
2848         } catch (final Throwable t) {
2849             fail("Threw " + t);
2850         }
2851 
2852         try {
2853             PropertyUtils.setIndexedProperty(bean,
2854                     "stringArray[0]",
2855                     "New Value 3");
2856             value =
2857                     PropertyUtils.getIndexedProperty(bean,
2858                             "stringArray[0]");
2859             assertNotNull("Returned new value 7", value);
2860             assertTrue("Returned String new value 7",
2861                     value instanceof String);
2862             assertEquals("Returned correct new value 7", "New Value 3",
2863                     (String) value);
2864         } catch (final Throwable t) {
2865             fail("Threw " + t);
2866         }
2867 
2868         // Index out of bounds tests
2869 
2870         try {
2871             PropertyUtils.setIndexedProperty(bean,
2872                     "dupProperty", -1,
2873                     "New -1");
2874             fail("Should have thrown ArrayIndexOutOfBoundsException");
2875         } catch (final ArrayIndexOutOfBoundsException t) {
2876             // Expected results
2877         } catch (final Throwable t) {
2878             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2879         }
2880 
2881         try {
2882             PropertyUtils.setIndexedProperty(bean,
2883                     "dupProperty", 5,
2884                     "New 5");
2885             fail("Should have thrown ArrayIndexOutOfBoundsException");
2886         } catch (final ArrayIndexOutOfBoundsException t) {
2887             // Expected results
2888         } catch (final Throwable t) {
2889             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2890         }
2891 
2892         try {
2893             PropertyUtils.setIndexedProperty(bean,
2894                     "intArray", -1,
2895                     new Integer(0));
2896             fail("Should have thrown ArrayIndexOutOfBoundsException");
2897         } catch (final ArrayIndexOutOfBoundsException t) {
2898             // Expected results
2899         } catch (final Throwable t) {
2900             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2901         }
2902 
2903         try {
2904             PropertyUtils.setIndexedProperty(bean,
2905                     "intArray", 5,
2906                     new Integer(0));
2907             fail("Should have thrown ArrayIndexOutOfBoundsException");
2908         } catch (final ArrayIndexOutOfBoundsException t) {
2909             // Expected results
2910         } catch (final Throwable t) {
2911             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2912         }
2913 
2914         try {
2915             PropertyUtils.setIndexedProperty(bean,
2916                     "intIndexed", -1,
2917                     new Integer(0));
2918             fail("Should have thrown ArrayIndexOutOfBoundsException");
2919         } catch (final ArrayIndexOutOfBoundsException t) {
2920             // Expected results
2921         } catch (final Throwable t) {
2922             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2923         }
2924 
2925         try {
2926             PropertyUtils.setIndexedProperty(bean,
2927                     "intIndexed", 5,
2928                     new Integer(0));
2929             fail("Should have thrown ArrayIndexOutOfBoundsException");
2930         } catch (final ArrayIndexOutOfBoundsException t) {
2931             // Expected results
2932         } catch (final Throwable t) {
2933             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2934         }
2935 
2936         try {
2937             PropertyUtils.setIndexedProperty(bean,
2938                     "listIndexed", 5,
2939                     "New String");
2940             fail("Should have thrown IndexOutOfBoundsException");
2941         } catch (final IndexOutOfBoundsException t) {
2942             // Expected results
2943         } catch (final Throwable t) {
2944             fail("Threw " + t + " instead of IndexOutOfBoundsException");
2945         }
2946 
2947         try {
2948             PropertyUtils.setIndexedProperty(bean,
2949                     "listIndexed", -1,
2950                     "New String");
2951             fail("Should have thrown IndexOutOfBoundsException");
2952         } catch (final IndexOutOfBoundsException t) {
2953             // Expected results
2954         } catch (final Throwable t) {
2955             fail("Threw " + t + " instead of IndexOutOfBoundsException");
2956         }
2957 
2958         try {
2959             PropertyUtils.setIndexedProperty(bean,
2960                     "stringArray", -1,
2961                     "New String");
2962             fail("Should have thrown ArrayIndexOutOfBoundsException");
2963         } catch (final ArrayIndexOutOfBoundsException t) {
2964             // Expected results
2965         } catch (final Throwable t) {
2966             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2967         }
2968 
2969         try {
2970             PropertyUtils.setIndexedProperty(bean,
2971                     "stringArray", 5,
2972                     "New String");
2973             fail("Should have thrown ArrayIndexOutOfBoundsException");
2974         } catch (final ArrayIndexOutOfBoundsException t) {
2975             // Expected results
2976         } catch (final Throwable t) {
2977             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2978         }
2979 
2980         try {
2981             PropertyUtils.setIndexedProperty(bean,
2982                     "stringIndexed", -1,
2983                     "New String");
2984             fail("Should have thrown ArrayIndexOutOfBoundsException");
2985         } catch (final ArrayIndexOutOfBoundsException t) {
2986             // Expected results
2987         } catch (final Throwable t) {
2988             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
2989         }
2990 
2991         try {
2992             PropertyUtils.setIndexedProperty(bean,
2993                     "stringIndexed", 5,
2994                     "New String");
2995             fail("Should have thrown ArrayIndexOutOfBoundsException");
2996         } catch (final ArrayIndexOutOfBoundsException t) {
2997             // Expected results
2998         } catch (final Throwable t) {
2999             fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
3000         }
3001 
3002     }
3003 
3004 
3005     /**
3006      * Corner cases on getMappedProperty invalid arguments.
3007      */
3008     public void testSetMappedArguments() {
3009 
3010         // Use explicit key argument
3011 
3012         try {
3013             PropertyUtils.setMappedProperty(null, "mappedProperty",
3014                     "First Key", "First Value");
3015             fail("Should throw IllegalArgumentException 1");
3016         } catch (final IllegalArgumentException e) {
3017             // Expected response
3018         } catch (final Throwable t) {
3019             fail("Threw " + t + " instead of IllegalArgumentException 1");
3020         }
3021 
3022         try {
3023             PropertyUtils.setMappedProperty(bean, null, "First Key",
3024                     "First Value");
3025             fail("Should throw IllegalArgumentException 2");
3026         } catch (final IllegalArgumentException e) {
3027             // Expected response
3028         } catch (final Throwable t) {
3029             fail("Threw " + t + " instead of IllegalArgumentException 2");
3030         }
3031 
3032         try {
3033             PropertyUtils.setMappedProperty(bean, "mappedProperty", null,
3034                     "First Value");
3035             fail("Should throw IllegalArgumentException 3");
3036         } catch (final IllegalArgumentException e) {
3037             // Expected response
3038         } catch (final Throwable t) {
3039             fail("Threw " + t + " instead of IllegalArgumentException 3");
3040         }
3041 
3042         // Use key expression
3043 
3044         try {
3045             PropertyUtils.setMappedProperty(null,
3046                     "mappedProperty(First Key)",
3047                     "First Value");
3048             fail("Should throw IllegalArgumentException 4");
3049         } catch (final IllegalArgumentException e) {
3050             // Expected response
3051         } catch (final Throwable t) {
3052             fail("Threw " + t + " instead of IllegalArgumentException 4");
3053         }
3054 
3055         try {
3056             PropertyUtils.setMappedProperty(bean, "(Second Key)",
3057                     "Second Value");
3058             fail("Should throw IllegalArgumentException 5");
3059         } catch (final NoSuchMethodException e) {
3060             // Expected response
3061         } catch (final Throwable t) {
3062             fail("Threw " + t + " instead of NoSuchMethodException 5");
3063         }
3064 
3065         try {
3066             PropertyUtils.setMappedProperty(bean, "mappedProperty",
3067                     "Third Value");
3068             fail("Should throw IllegalArgumentException 6");
3069         } catch (final IllegalArgumentException e) {
3070             // Expected response
3071         } catch (final Throwable t) {
3072             fail("Threw " + t + " instead of IllegalArgumentException 6");
3073         }
3074 
3075     }
3076 
3077 
3078     /**
3079      * Test setting an indexed value out of a mapped array
3080      */
3081     public void testSetMappedArray() {
3082         final TestBean bean = new TestBean();
3083         final String[] array = new String[] {"abc", "def", "ghi"};
3084         bean.getMapProperty().put("mappedArray", array);
3085 
3086         assertEquals("BEFORE", "def", ((String[])bean.getMapProperty().get("mappedArray"))[1]);
3087         try {
3088             PropertyUtils.setProperty(bean, "mapProperty(mappedArray)[1]", "DEF-UPDATED");
3089         } catch (final Throwable t) {
3090             fail("Threw " + t + "");
3091         }
3092         assertEquals("AFTER", "DEF-UPDATED", ((String[])bean.getMapProperty().get("mappedArray"))[1]);
3093     }
3094 
3095     /**
3096      * Test setting an indexed value out of a mapped List
3097      */
3098     public void testSetMappedList() {
3099         final TestBean bean = new TestBean();
3100         final List<Object> list = new ArrayList<Object>();
3101         list.add("klm");
3102         list.add("nop");
3103         list.add("qrs");
3104         bean.getMapProperty().put("mappedList", list);
3105 
3106         assertEquals("BEFORE", "klm", ((List<?>)bean.getMapProperty().get("mappedList")).get(0));
3107         try {
3108             PropertyUtils.setProperty(bean, "mapProperty(mappedList)[0]", "KLM-UPDATED");
3109         } catch (final Throwable t) {
3110             fail("Threw " + t + "");
3111         }
3112         assertEquals("AFTER", "KLM-UPDATED", ((List<?>)bean.getMapProperty().get("mappedList")).get(0));
3113     }
3114 
3115     /**
3116      * Test setting a value out of a mapped Map
3117      */
3118     public void testSetMappedMap() {
3119         final TestBean bean = new TestBean();
3120         final Map<String, Object> map = new HashMap<String, Object>();
3121         map.put("sub-key-1", "sub-value-1");
3122         map.put("sub-key-2", "sub-value-2");
3123         map.put("sub-key-3", "sub-value-3");
3124         bean.getMapProperty().put("mappedMap", map);
3125 
3126         assertEquals("BEFORE", "sub-value-3", ((Map<?, ?>)bean.getMapProperty().get("mappedMap")).get("sub-key-3"));
3127         try {
3128             PropertyUtils.setProperty(bean, "mapProperty(mappedMap)(sub-key-3)", "SUB-KEY-3-UPDATED");
3129         } catch (final Throwable t) {
3130             fail("Threw " + t + "");
3131         }
3132         assertEquals("AFTER", "SUB-KEY-3-UPDATED", ((Map<?, ?>)bean.getMapProperty().get("mappedMap")).get("sub-key-3"));
3133     }
3134 
3135     /**
3136      * Positive and negative tests on setMappedProperty valid arguments.
3137      */
3138     public void testSetMappedValues() {
3139 
3140         Object value = null;
3141 
3142         // Use explicit key argument
3143 
3144         try {
3145             value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
3146                     "Fourth Key");
3147             assertNull("Can not find fourth value", value);
3148         } catch (final Throwable t) {
3149             fail("Finding fourth value threw " + t);
3150         }
3151 
3152         try {
3153             PropertyUtils.setMappedProperty(bean, "mappedProperty",
3154                     "Fourth Key", "Fourth Value");
3155         } catch (final Throwable t) {
3156             fail("Setting fourth value threw " + t);
3157         }
3158 
3159         try {
3160             value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
3161                     "Fourth Key");
3162             assertEquals("Can find fourth value", "Fourth Value", value);
3163         } catch (final Throwable t) {
3164             fail("Finding fourth value threw " + t);
3165         }
3166 
3167         // Use key expression with parentheses
3168 
3169         try {
3170             value =
3171                     PropertyUtils.getMappedProperty(bean,
3172                             "mappedProperty(Fifth Key)");
3173             assertNull("Can not find fifth value", value);
3174         } catch (final Throwable t) {
3175             fail("Finding fifth value threw " + t);
3176         }
3177 
3178         try {
3179             PropertyUtils.setMappedProperty(bean,
3180                     "mappedProperty(Fifth Key)",
3181                     "Fifth Value");
3182         } catch (final Throwable t) {
3183             fail("Setting fifth value threw " + t);
3184         }
3185 
3186         try {
3187             value =
3188                     PropertyUtils.getMappedProperty(bean,
3189                             "mappedProperty(Fifth Key)");
3190             assertEquals("Can find fifth value", "Fifth Value", value);
3191         } catch (final Throwable t) {
3192             fail("Finding fifth value threw " + t);
3193         }
3194 
3195         // Use key expression with dotted expression
3196 
3197         try {
3198             value =
3199                     PropertyUtils.getNestedProperty(bean,
3200                             "mapProperty.Sixth Key");
3201             assertNull("Can not find sixth value", value);
3202         } catch (final Throwable t) {
3203             fail("Finding fifth value threw " + t);
3204         }
3205 
3206         try {
3207             PropertyUtils.setNestedProperty(bean,
3208                     "mapProperty.Sixth Key",
3209                     "Sixth Value");
3210         } catch (final Throwable t) {
3211             fail("Setting sixth value threw " + t);
3212         }
3213 
3214         try {
3215             value =
3216                     PropertyUtils.getNestedProperty(bean,
3217                             "mapProperty.Sixth Key");
3218             assertEquals("Can find sixth value", "Sixth Value", value);
3219         } catch (final Throwable t) {
3220             fail("Finding sixth value threw " + t);
3221         }
3222 
3223     }
3224 
3225     /**
3226      * Test setting mapped values with periods in the key.
3227      */
3228     public void testSetMappedPeriods() {
3229 
3230 
3231         // -------- PropertyUtils.setMappedProperty()--------
3232         bean.setMappedProperty("key.with.a.dot", "Special Value");
3233         assertEquals("Can retrieve directly (A)",
3234                      "Special Value",
3235                      bean.getMappedProperty("key.with.a.dot"));
3236 
3237         try {
3238             PropertyUtils.setMappedProperty(bean, "mappedProperty", "key.with.a.dot", "Updated Special Value");
3239             assertEquals("Check set via setMappedProperty",
3240                          "Updated Special Value",
3241                           bean.getMappedProperty("key.with.a.dot"));
3242         } catch (final Exception e) {
3243             fail("Thew exception: " + e);
3244         }
3245 
3246         // -------- PropertyUtils.setNestedProperty() --------
3247         bean.setMappedProperty("key.with.a.dot", "Special Value");
3248         assertEquals("Can retrieve directly (B)",
3249                      "Special Value",
3250                      bean.getMappedProperty("key.with.a.dot"));
3251         try {
3252             PropertyUtils.setNestedProperty(bean, "mappedProperty(key.with.a.dot)", "Updated Special Value");
3253             assertEquals("Check set via setNestedProperty (B)",
3254                          "Updated Special Value",
3255                          bean.getMappedProperty("key.with.a.dot"));
3256         } catch (final Exception e) {
3257             fail("Thew exception: " + e);
3258         }
3259 
3260 
3261         // -------- PropertyUtils.setNestedProperty() --------
3262         final TestBean testBean = new TestBean();
3263         bean.setMappedObjects("nested.property", testBean);
3264         assertEquals("Can retrieve directly (C)",
3265                      "This is a string",
3266                      testBean.getStringProperty());
3267         try {
3268             PropertyUtils.setNestedProperty(bean, "mappedObjects(nested.property).stringProperty",
3269                                                   "Updated String Value");
3270             assertEquals("Check set via setNestedProperty (C)",
3271                          "Updated String Value",
3272                          testBean.getStringProperty());
3273         } catch (final Exception e) {
3274             fail("Thew exception: " + e);
3275         }
3276 
3277         // -------- PropertyUtils.setNestedProperty() --------
3278         bean.getNested().setMappedProperty("Mapped Key", "Nested Mapped Value");
3279         try {
3280             assertEquals("Can retrieve via getNestedProperty (D)",
3281                          "Nested Mapped Value",
3282                          PropertyUtils.getNestedProperty(
3283                              bean,"nested.mappedProperty(Mapped Key)"));
3284             PropertyUtils.setNestedProperty(bean, "nested.mappedProperty(Mapped Key)",
3285                                                   "Updated Nested Mapped Value");
3286             assertEquals("Check set via setNestedProperty (D)",
3287                          "Updated Nested Mapped Value",
3288                          PropertyUtils.getNestedProperty(
3289                              bean,"nested.mappedProperty(Mapped Key)"));
3290         } catch (final Exception e) {
3291             fail("Thew exception: " + e);
3292         }
3293     }
3294 
3295 
3296     /**
3297      * Corner cases on setNestedProperty invalid arguments.
3298      */
3299     public void testSetNestedArguments() {
3300 
3301         try {
3302             PropertyUtils.setNestedProperty(null, "stringProperty", "");
3303             fail("Should throw IllegalArgumentException 1");
3304         } catch (final IllegalArgumentException e) {
3305             // Expected response
3306         } catch (final Throwable t) {
3307             fail("Threw " + t + " instead of IllegalArgumentException 1");
3308         }
3309 
3310         try {
3311             PropertyUtils.setNestedProperty(bean, null, "");
3312             fail("Should throw IllegalArgumentException 2");
3313         } catch (final IllegalArgumentException e) {
3314             // Expected response
3315         } catch (final Throwable t) {
3316             fail("Threw " + t + " instead of IllegalArgumentException 2");
3317         }
3318 
3319     }
3320 
3321 
3322     /**
3323      * Test setNextedProperty on a boolean property.
3324      */
3325     public void testSetNestedBoolean() {
3326 
3327         try {
3328             final boolean oldValue = bean.getNested().getBooleanProperty();
3329             final boolean newValue = !oldValue;
3330             PropertyUtils.setNestedProperty(bean,
3331                     "nested.booleanProperty",
3332                     new Boolean(newValue));
3333             assertTrue("Matched new value",
3334                     newValue ==
3335                     bean.getNested().getBooleanProperty());
3336         } catch (final IllegalAccessException e) {
3337             fail("IllegalAccessException");
3338         } catch (final IllegalArgumentException e) {
3339             fail("IllegalArgumentException");
3340         } catch (final InvocationTargetException e) {
3341             fail("InvocationTargetException");
3342         } catch (final NoSuchMethodException e) {
3343             fail("NoSuchMethodException");
3344         }
3345 
3346     }
3347 
3348 
3349     /**
3350      * Test setNestedProperty on a double property.
3351      */
3352     public void testSetNestedDouble() {
3353 
3354         try {
3355             final double oldValue = bean.getNested().getDoubleProperty();
3356             final double newValue = oldValue + 1.0;
3357             PropertyUtils.setNestedProperty(bean,
3358                     "nested.doubleProperty",
3359                     new Double(newValue));
3360             assertEquals("Matched new value",
3361                     newValue,
3362                     bean.getNested().getDoubleProperty(),
3363                     0.005);
3364         } catch (final IllegalAccessException e) {
3365             fail("IllegalAccessException");
3366         } catch (final IllegalArgumentException e) {
3367             fail("IllegalArgumentException");
3368         } catch (final InvocationTargetException e) {
3369             fail("InvocationTargetException");
3370         } catch (final NoSuchMethodException e) {
3371             fail("NoSuchMethodException");
3372         }
3373 
3374     }
3375 
3376 
3377     /**
3378      * Test setNestedProperty on a float property.
3379      */
3380     public void testSetNestedFloat() {
3381 
3382         try {
3383             final float oldValue = bean.getNested().getFloatProperty();
3384             final float newValue = oldValue + (float) 1.0;
3385             PropertyUtils.setNestedProperty(bean,
3386                     "nested.floatProperty",
3387                     new Float(newValue));
3388             assertEquals("Matched new value",
3389                     newValue,
3390                     bean.getNested().getFloatProperty(),
3391                     (float) 0.005);
3392         } catch (final IllegalAccessException e) {
3393             fail("IllegalAccessException");
3394         } catch (final IllegalArgumentException e) {
3395             fail("IllegalArgumentException");
3396         } catch (final InvocationTargetException e) {
3397             fail("InvocationTargetException");
3398         } catch (final NoSuchMethodException e) {
3399             fail("NoSuchMethodException");
3400         }
3401 
3402     }
3403 
3404 
3405     /**
3406      * Test setNestedProperty on a int property.
3407      */
3408     public void testSetNestedInt() {
3409 
3410         try {
3411             final int oldValue = bean.getNested().getIntProperty();
3412             final int newValue = oldValue + 1;
3413             PropertyUtils.setNestedProperty(bean,
3414                     "nested.intProperty",
3415                     new Integer(newValue));
3416             assertEquals("Matched new value",
3417                     newValue,
3418                     bean.getNested().getIntProperty());
3419         } catch (final IllegalAccessException e) {
3420             fail("IllegalAccessException");
3421         } catch (final IllegalArgumentException e) {
3422             fail("IllegalArgumentException");
3423         } catch (final InvocationTargetException e) {
3424             fail("InvocationTargetException");
3425         } catch (final NoSuchMethodException e) {
3426             fail("NoSuchMethodException");
3427         }
3428 
3429     }
3430 
3431 
3432     /**
3433      * Test setNestedProperty on a long property.
3434      */
3435     public void testSetNestedLong() {
3436 
3437         try {
3438             final long oldValue = bean.getNested().getLongProperty();
3439             final long newValue = oldValue + 1;
3440             PropertyUtils.setNestedProperty(bean,
3441                     "nested.longProperty",
3442                     new Long(newValue));
3443             assertEquals("Matched new value",
3444                     newValue,
3445                     bean.getNested().getLongProperty());
3446         } catch (final IllegalAccessException e) {
3447             fail("IllegalAccessException");
3448         } catch (final IllegalArgumentException e) {
3449             fail("IllegalArgumentException");
3450         } catch (final InvocationTargetException e) {
3451             fail("InvocationTargetException");
3452         } catch (final NoSuchMethodException e) {
3453             fail("NoSuchMethodException");
3454         }
3455 
3456     }
3457 
3458 
3459     /**
3460      * Test setNestedProperty on a read-only String property.
3461      */
3462     public void testSetNestedReadOnly() {
3463 
3464         try {
3465             final String oldValue = bean.getNested().getWriteOnlyPropertyValue();
3466             final String newValue = oldValue + " Extra Value";
3467             PropertyUtils.setNestedProperty(bean,
3468                     "nested.readOnlyProperty",
3469                     newValue);
3470             fail("Should have thrown NoSuchMethodException");
3471         } catch (final IllegalAccessException e) {
3472             fail("IllegalAccessException");
3473         } catch (final IllegalArgumentException e) {
3474             fail("IllegalArgumentException");
3475         } catch (final InvocationTargetException e) {
3476             fail("InvocationTargetException");
3477         } catch (final NoSuchMethodException e) {
3478             // Correct result for this test
3479         }
3480 
3481     }
3482 
3483 
3484     /**
3485      * Test setNestedProperty on a short property.
3486      */
3487     public void testSetNestedShort() {
3488 
3489         try {
3490             final short oldValue = bean.getNested().getShortProperty();
3491             short newValue = oldValue;
3492             newValue++;
3493             PropertyUtils.setNestedProperty(bean,
3494                     "nested.shortProperty",
3495                     new Short(newValue));
3496             assertEquals("Matched new value",
3497                     newValue,
3498                     bean.getNested().getShortProperty());
3499         } catch (final IllegalAccessException e) {
3500             fail("IllegalAccessException");
3501         } catch (final IllegalArgumentException e) {
3502             fail("IllegalArgumentException");
3503         } catch (final InvocationTargetException e) {
3504             fail("InvocationTargetException");
3505         } catch (final NoSuchMethodException e) {
3506             fail("NoSuchMethodException");
3507         }
3508 
3509     }
3510 
3511 
3512     /**
3513      * Test setNestedProperty on a String property.
3514      */
3515     public void testSetNestedString() {
3516 
3517         try {
3518             final String oldValue = bean.getNested().getStringProperty();
3519             final String newValue = oldValue + " Extra Value";
3520             PropertyUtils.setNestedProperty(bean,
3521                     "nested.stringProperty",
3522                     newValue);
3523             assertEquals("Matched new value",
3524                     newValue,
3525                     bean.getNested().getStringProperty());
3526         } catch (final IllegalAccessException e) {
3527             fail("IllegalAccessException");
3528         } catch (final IllegalArgumentException e) {
3529             fail("IllegalArgumentException");
3530         } catch (final InvocationTargetException e) {
3531             fail("InvocationTargetException");
3532         } catch (final NoSuchMethodException e) {
3533             fail("NoSuchMethodException");
3534         }
3535 
3536     }
3537 
3538 
3539     /**
3540      * Test setNestedProperty on an unknown property name.
3541      */
3542     public void testSetNestedUnknown() {
3543 
3544         try {
3545             final String newValue = "New String Value";
3546             PropertyUtils.setNestedProperty(bean,
3547                     "nested.unknown",
3548                     newValue);
3549             fail("Should have thrown NoSuchMethodException");
3550         } catch (final IllegalAccessException e) {
3551             fail("IllegalAccessException");
3552         } catch (final IllegalArgumentException e) {
3553             fail("IllegalArgumentException");
3554         } catch (final InvocationTargetException e) {
3555             fail("InvocationTargetException");
3556         } catch (final NoSuchMethodException e) {
3557             // Correct result for this test
3558         }
3559 
3560     }
3561 
3562 
3563     /**
3564      * Test setNestedProperty on a write-only String property.
3565      */
3566     public void testSetNestedWriteOnly() {
3567 
3568         try {
3569             final String oldValue = bean.getNested().getWriteOnlyPropertyValue();
3570             final String newValue = oldValue + " Extra Value";
3571             PropertyUtils.setNestedProperty(bean,
3572                     "nested.writeOnlyProperty",
3573                     newValue);
3574             assertEquals("Matched new value",
3575                     newValue,
3576                     bean.getNested().getWriteOnlyPropertyValue());
3577         } catch (final IllegalAccessException e) {
3578             fail("IllegalAccessException");
3579         } catch (final IllegalArgumentException e) {
3580             fail("IllegalArgumentException");
3581         } catch (final InvocationTargetException e) {
3582             fail("InvocationTargetException");
3583         } catch (final NoSuchMethodException e) {
3584             fail("NoSuchMethodException");
3585         }
3586 
3587     }
3588 
3589 
3590     /**
3591      * Corner cases on setSimpleProperty invalid arguments.
3592      */
3593     public void testSetSimpleArguments() {
3594 
3595         try {
3596             PropertyUtils.setSimpleProperty(null, "stringProperty", "");
3597             fail("Should throw IllegalArgumentException 1");
3598         } catch (final IllegalArgumentException e) {
3599             // Expected response
3600         } catch (final Throwable t) {
3601             fail("Threw " + t + " instead of IllegalArgumentException 1");
3602         }
3603 
3604         try {
3605             PropertyUtils.setSimpleProperty(bean, null, "");
3606             fail("Should throw IllegalArgumentException 2");
3607         } catch (final IllegalArgumentException e) {
3608             // Expected response
3609         } catch (final Throwable t) {
3610             fail("Threw " + t + " instead of IllegalArgumentException 2");
3611         }
3612 
3613     }
3614 
3615 
3616     /**
3617      * Test setSimpleProperty on a boolean property.
3618      */
3619     public void testSetSimpleBoolean() {
3620 
3621         try {
3622             final boolean oldValue = bean.getBooleanProperty();
3623             final boolean newValue = !oldValue;
3624             PropertyUtils.setSimpleProperty(bean,
3625                     "booleanProperty",
3626                     new Boolean(newValue));
3627             assertTrue("Matched new value",
3628                     newValue ==
3629                     bean.getBooleanProperty());
3630         } catch (final IllegalAccessException e) {
3631             fail("IllegalAccessException");
3632         } catch (final IllegalArgumentException e) {
3633             fail("IllegalArgumentException");
3634         } catch (final InvocationTargetException e) {
3635             fail("InvocationTargetException");
3636         } catch (final NoSuchMethodException e) {
3637             fail("NoSuchMethodException");
3638         }
3639 
3640     }
3641 
3642 
3643     /**
3644      * Test setSimpleProperty on a double property.
3645      */
3646     public void testSetSimpleDouble() {
3647 
3648         try {
3649             final double oldValue = bean.getDoubleProperty();
3650             final double newValue = oldValue + 1.0;
3651             PropertyUtils.setSimpleProperty(bean,
3652                     "doubleProperty",
3653                     new Double(newValue));
3654             assertEquals("Matched new value",
3655                     newValue,
3656                     bean.getDoubleProperty(),
3657                     0.005);
3658         } catch (final IllegalAccessException e) {
3659             fail("IllegalAccessException");
3660         } catch (final IllegalArgumentException e) {
3661             fail("IllegalArgumentException");
3662         } catch (final InvocationTargetException e) {
3663             fail("InvocationTargetException");
3664         } catch (final NoSuchMethodException e) {
3665             fail("NoSuchMethodException");
3666         }
3667 
3668     }
3669 
3670 
3671     /**
3672      * Test setSimpleProperty on a float property.
3673      */
3674     public void testSetSimpleFloat() {
3675 
3676         try {
3677             final float oldValue = bean.getFloatProperty();
3678             final float newValue = oldValue + (float) 1.0;
3679             PropertyUtils.setSimpleProperty(bean,
3680                     "floatProperty",
3681                     new Float(newValue));
3682             assertEquals("Matched new value",
3683                     newValue,
3684                     bean.getFloatProperty(),
3685                     (float) 0.005);
3686         } catch (final IllegalAccessException e) {
3687             fail("IllegalAccessException");
3688         } catch (final IllegalArgumentException e) {
3689             fail("IllegalArgumentException");
3690         } catch (final InvocationTargetException e) {
3691             fail("InvocationTargetException");
3692         } catch (final NoSuchMethodException e) {
3693             fail("NoSuchMethodException");
3694         }
3695 
3696     }
3697 
3698 
3699     /**
3700      * Negative test setSimpleProperty on an indexed property.
3701      */
3702     public void testSetSimpleIndexed() {
3703 
3704         try {
3705             PropertyUtils.setSimpleProperty(bean,
3706                     "stringIndexed[0]",
3707                     "New String Value");
3708             fail("Should have thrown IllegalArgumentException");
3709         } catch (final IllegalAccessException e) {
3710             fail("IllegalAccessException");
3711         } catch (final IllegalArgumentException e) {
3712             // Correct result for this test
3713         } catch (final InvocationTargetException e) {
3714             fail("InvocationTargetException");
3715         } catch (final NoSuchMethodException e) {
3716             fail("NoSuchMethodException");
3717         }
3718 
3719     }
3720 
3721 
3722     /**
3723      * Test setSimpleProperty on a int property.
3724      */
3725     public void testSetSimpleInt() {
3726 
3727         try {
3728             final int oldValue = bean.getIntProperty();
3729             final int newValue = oldValue + 1;
3730             PropertyUtils.setSimpleProperty(bean,
3731                     "intProperty",
3732                     new Integer(newValue));
3733             assertEquals("Matched new value",
3734                     newValue,
3735                     bean.getIntProperty());
3736         } catch (final IllegalAccessException e) {
3737             fail("IllegalAccessException");
3738         } catch (final IllegalArgumentException e) {
3739             fail("IllegalArgumentException");
3740         } catch (final InvocationTargetException e) {
3741             fail("InvocationTargetException");
3742         } catch (final NoSuchMethodException e) {
3743             fail("NoSuchMethodException");
3744         }
3745 
3746     }
3747 
3748 
3749     /**
3750      * Test setSimpleProperty on a long property.
3751      */
3752     public void testSetSimpleLong() {
3753 
3754         try {
3755             final long oldValue = bean.getLongProperty();
3756             final long newValue = oldValue + 1;
3757             PropertyUtils.setSimpleProperty(bean,
3758                     "longProperty",
3759                     new Long(newValue));
3760             assertEquals("Matched new value",
3761                     newValue,
3762                     bean.getLongProperty());
3763         } catch (final IllegalAccessException e) {
3764             fail("IllegalAccessException");
3765         } catch (final IllegalArgumentException e) {
3766             fail("IllegalArgumentException");
3767         } catch (final InvocationTargetException e) {
3768             fail("InvocationTargetException");
3769         } catch (final NoSuchMethodException e) {
3770             fail("NoSuchMethodException");
3771         }
3772 
3773     }
3774 
3775 
3776     /**
3777      * Negative test setSimpleProperty on a nested property.
3778      */
3779     public void testSetSimpleNested() {
3780 
3781         try {
3782             PropertyUtils.setSimpleProperty(bean,
3783                     "nested.stringProperty",
3784                     "New String Value");
3785             fail("Should have thrown IllegalArgumentException");
3786         } catch (final IllegalAccessException e) {
3787             fail("IllegalAccessException");
3788         } catch (final IllegalArgumentException e) {
3789             // Correct result for this test
3790         } catch (final InvocationTargetException e) {
3791             fail("InvocationTargetException");
3792         } catch (final NoSuchMethodException e) {
3793             fail("NoSuchMethodException");
3794         }
3795 
3796     }
3797 
3798 
3799     /**
3800      * Test setSimpleProperty on a read-only String property.
3801      */
3802     public void testSetSimpleReadOnly() {
3803 
3804         try {
3805             final String oldValue = bean.getWriteOnlyPropertyValue();
3806             final String newValue = oldValue + " Extra Value";
3807             PropertyUtils.setSimpleProperty(bean,
3808                     "readOnlyProperty",
3809                     newValue);
3810             fail("Should have thrown NoSuchMethodException");
3811         } catch (final IllegalAccessException e) {
3812             fail("IllegalAccessException");
3813         } catch (final IllegalArgumentException e) {
3814             fail("IllegalArgumentException");
3815         } catch (final InvocationTargetException e) {
3816             fail("InvocationTargetException");
3817         } catch (final NoSuchMethodException e) {
3818             // Correct result for this test
3819             assertEquals("Property 'readOnlyProperty' has no setter method in class '" +
3820                          bean.getClass() + "'", e.getMessage() );
3821         }
3822 
3823     }
3824 
3825 
3826     /**
3827      * Test setSimpleProperty on a short property.
3828      */
3829     public void testSetSimpleShort() {
3830 
3831         try {
3832             final short oldValue = bean.getShortProperty();
3833             short newValue = oldValue;
3834             newValue++;
3835             PropertyUtils.setSimpleProperty(bean,
3836                     "shortProperty",
3837                     new Short(newValue));
3838             assertEquals("Matched new value",
3839                     newValue,
3840                     bean.getShortProperty());
3841         } catch (final IllegalAccessException e) {
3842             fail("IllegalAccessException");
3843         } catch (final IllegalArgumentException e) {
3844             fail("IllegalArgumentException");
3845         } catch (final InvocationTargetException e) {
3846             fail("InvocationTargetException");
3847         } catch (final NoSuchMethodException e) {
3848             fail("NoSuchMethodException");
3849         }
3850 
3851     }
3852 
3853 
3854     /**
3855      * Test setSimpleProperty on a String property.
3856      */
3857     public void testSetSimpleString() {
3858 
3859         try {
3860             final String oldValue = bean.getStringProperty();
3861             final String newValue = oldValue + " Extra Value";
3862             PropertyUtils.setSimpleProperty(bean,
3863                     "stringProperty",
3864                     newValue);
3865             assertEquals("Matched new value",
3866                     newValue,
3867                     bean.getStringProperty());
3868         } catch (final IllegalAccessException e) {
3869             fail("IllegalAccessException");
3870         } catch (final IllegalArgumentException e) {
3871             fail("IllegalArgumentException");
3872         } catch (final InvocationTargetException e) {
3873             fail("InvocationTargetException");
3874         } catch (final NoSuchMethodException e) {
3875             fail("NoSuchMethodException");
3876         }
3877 
3878     }
3879 
3880 
3881     /**
3882      * Test setSimpleProperty on an unknown property name.
3883      */
3884     public void testSetSimpleUnknown() {
3885 
3886         try {
3887             final String newValue = "New String Value";
3888             PropertyUtils.setSimpleProperty(bean,
3889                     "unknown",
3890                     newValue);
3891             fail("Should have thrown NoSuchMethodException");
3892         } catch (final IllegalAccessException e) {
3893             fail("IllegalAccessException");
3894         } catch (final IllegalArgumentException e) {
3895             fail("IllegalArgumentException");
3896         } catch (final InvocationTargetException e) {
3897             fail("InvocationTargetException");
3898         } catch (final NoSuchMethodException e) {
3899             // Correct result for this test
3900             assertEquals("Unknown property 'unknown' on class '" +
3901                          bean.getClass() + "'", e.getMessage() );
3902         }
3903 
3904     }
3905 
3906 
3907     /**
3908      * Test setSimpleProperty on a write-only String property.
3909      */
3910     public void testSetSimpleWriteOnly() {
3911 
3912         try {
3913             final String oldValue = bean.getWriteOnlyPropertyValue();
3914             final String newValue = oldValue + " Extra Value";
3915             PropertyUtils.setSimpleProperty(bean,
3916                     "writeOnlyProperty",
3917                     newValue);
3918             assertEquals("Matched new value",
3919                     newValue,
3920                     bean.getWriteOnlyPropertyValue());
3921         } catch (final IllegalAccessException e) {
3922             fail("IllegalAccessException");
3923         } catch (final IllegalArgumentException e) {
3924             fail("IllegalArgumentException");
3925         } catch (final InvocationTargetException e) {
3926             fail("InvocationTargetException");
3927         } catch (final NoSuchMethodException e) {
3928             fail("NoSuchMethodException");
3929         }
3930 
3931     }
3932 
3933 
3934     // ------------------------------------------------------ Protected Methods
3935 
3936 
3937     /**
3938      * Base for testGetDescriptorXxxxx() series of tests.
3939      *
3940      * @param name Name of the property to be retrieved
3941      * @param read Expected name of the read method (or null)
3942      * @param write Expected name of the write method (or null)
3943      */
3944     protected void testGetDescriptorBase(final String name, final String read,
3945                                          final String write) {
3946 
3947         try {
3948             final PropertyDescriptor pd =
3949                     PropertyUtils.getPropertyDescriptor(bean, name);
3950             if ((read != null) || (write != null)) {
3951                 assertNotNull("Got descriptor", pd);
3952             } else {
3953                 assertNull("Got descriptor", pd);
3954                 return;
3955             }
3956             final Method rm = pd.getReadMethod();
3957             if (read != null) {
3958                 assertNotNull("Got read method", rm);
3959                 assertEquals("Got correct read method",
3960                         rm.getName(), read);
3961             } else {
3962                 assertNull("Got read method", rm);
3963             }
3964             final Method wm = pd.getWriteMethod();
3965             if (write != null) {
3966                 assertNotNull("Got write method", wm);
3967                 assertEquals("Got correct write method",
3968                         wm.getName(), write);
3969             } else {
3970                 assertNull("Got write method", wm);
3971             }
3972         } catch (final IllegalAccessException e) {
3973             fail("IllegalAccessException");
3974         } catch (final InvocationTargetException e) {
3975             fail("InvocationTargetException");
3976         } catch (final NoSuchMethodException e) {
3977             fail("NoSuchMethodException");
3978         }
3979 
3980     }
3981 
3982 
3983     /**
3984      * Base for testGetReadMethod() series of tests.
3985      *
3986      * @param bean Bean for which to retrieve read methods.
3987      * @param properties Property names to search for
3988      * @param className Class name where this method should be defined
3989      */
3990     protected void testGetReadMethod(final Object bean, final String properties[],
3991                                      final String className) {
3992 
3993         final PropertyDescriptor pd[] =
3994                 PropertyUtils.getPropertyDescriptors(bean);
3995         for (String propertie : properties) {
3996 
3997             // Identify the property descriptor for this property
3998             if (propertie.equals("intIndexed")) {
3999                 continue;
4000             }
4001             if (propertie.equals("stringIndexed")) {
4002                 continue;
4003             }
4004             if (propertie.equals("writeOnlyProperty")) {
4005                 continue;
4006             }
4007             int n = -1;
4008             for (int j = 0; j < pd.length; j++) {
4009                 if (propertie.equals(pd[j].getName())) {
4010                     n = j;
4011                     break;
4012                 }
4013             }
4014             assertTrue("PropertyDescriptor for " + propertie,
4015                     n >= 0);
4016 
4017             // Locate an accessible property reader method for it
4018             final Method reader = PropertyUtils.getReadMethod(pd[n]);
4019             assertNotNull("Reader for " + propertie,
4020                     reader);
4021             final Class<?> clazz = reader.getDeclaringClass();
4022             assertNotNull("Declaring class for " + propertie,
4023                     clazz);
4024             assertEquals("Correct declaring class for " + propertie,
4025                     clazz.getName(),
4026                     className);
4027 
4028             // Actually call the reader method we received
4029             try {
4030                 reader.invoke(bean, (Object[]) new Class<?>[0]);
4031             } catch (final Throwable t) {
4032                 fail("Call for " + propertie + ": " + t);
4033             }
4034 
4035         }
4036 
4037     }
4038 
4039 
4040     /**
4041      * Base for testGetWriteMethod() series of tests.
4042      *
4043      * @param bean Bean for which to retrieve write methods.
4044      * @param properties Property names to search for
4045      * @param className Class name where this method should be defined
4046      */
4047     protected void testGetWriteMethod(final Object bean, final String properties[],
4048                                       final String className) {
4049 
4050 
4051         final PropertyDescriptor pd[] =
4052                 PropertyUtils.getPropertyDescriptors(bean);
4053         for (String propertie : properties) {
4054 
4055             // Identify the property descriptor for this property
4056             if (propertie.equals("intIndexed")) {
4057                 continue;
4058             }
4059             if (propertie.equals("listIndexed")) {
4060                 continue;
4061             }
4062             if (propertie.equals("nested"))
4063              {
4064                 continue; // This property is read only
4065             }
4066             if (propertie.equals("readOnlyProperty")) {
4067                 continue;
4068             }
4069             if (propertie.equals("stringIndexed")) {
4070                 continue;
4071             }
4072             int n = -1;
4073             for (int j = 0; j < pd.length; j++) {
4074                 if (propertie.equals(pd[j].getName())) {
4075                     n = j;
4076                     break;
4077                 }
4078             }
4079             assertTrue("PropertyDescriptor for " + propertie,
4080                     n >= 0);
4081 
4082             // Locate an accessible property reader method for it
4083             final Method writer = PropertyUtils.getWriteMethod(pd[n]);
4084             assertNotNull("Writer for " + propertie,
4085                     writer);
4086             final Class<?> clazz = writer.getDeclaringClass();
4087             assertNotNull("Declaring class for " + propertie,
4088                     clazz);
4089             assertEquals("Correct declaring class for " + propertie,
4090                     clazz.getName(),
4091                     className);
4092 
4093         }
4094 
4095     }
4096 
4097     public void testNestedWithIndex() throws Exception
4098     {
4099         final NestedTestBean nestedBean = new NestedTestBean("base");
4100         nestedBean.init();
4101         nestedBean.getSimpleBeanProperty().init();
4102 
4103         NestedTestBean
4104 
4105         // test first calling properties on indexed beans
4106 
4107         value = (NestedTestBean) PropertyUtils.getProperty(
4108                                 nestedBean,
4109                                 "indexedProperty[0]");
4110         assertEquals("Cannot get simple index(1)", "Bean@0", value.getName());
4111         assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
4112 
4113         value = (NestedTestBean) PropertyUtils.getProperty(
4114                                 nestedBean,
4115                                 "indexedProperty[1]");
4116         assertEquals("Cannot get simple index(1)", "Bean@1", value.getName());
4117         assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
4118 
4119         String
4120         prop = (String) PropertyUtils.getProperty(
4121                                 nestedBean,
4122                                 "indexedProperty[0].testString");
4123         assertEquals("Get property on indexes failed (1)", "NOT SET", prop);
4124 
4125         prop = (String) PropertyUtils.getProperty(
4126                                 nestedBean,
4127                                 "indexedProperty[1].testString");
4128         assertEquals("Get property on indexes failed (2)", "NOT SET", prop);
4129 
4130         PropertyUtils.setProperty(
4131                                 nestedBean,
4132                                 "indexedProperty[0].testString",
4133                                 "Test#1");
4134         assertEquals(
4135                 "Cannot set property on indexed bean (1)",
4136                 "Test#1",
4137                 nestedBean.getIndexedProperty(0).getTestString());
4138 
4139         PropertyUtils.setProperty(
4140                                 nestedBean,
4141                                 "indexedProperty[1].testString",
4142                                 "Test#2");
4143         assertEquals(
4144                 "Cannot set property on indexed bean (2)",
4145                 "Test#2",
4146                 nestedBean.getIndexedProperty(1).getTestString());
4147 
4148 
4149         // test first calling indexed properties on a simple property
4150 
4151         value = (NestedTestBean) PropertyUtils.getProperty(
4152                                 nestedBean,
4153                                 "simpleBeanProperty");
4154         assertEquals("Cannot get simple bean", "Simple Property Bean", value.getName());
4155         assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
4156 
4157         value = (NestedTestBean) PropertyUtils.getProperty(
4158                                 nestedBean,
4159                                 "simpleBeanProperty.indexedProperty[3]");
4160         assertEquals("Cannot get index property on property", "Bean@3", value.getName());
4161         assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
4162 
4163         PropertyUtils.setProperty(
4164                                 nestedBean,
4165                                 "simpleBeanProperty.indexedProperty[3].testString",
4166                                 "Test#3");
4167         assertEquals(
4168             "Cannot set property on indexed property on property",
4169             "Test#3",
4170             nestedBean.getSimpleBeanProperty().getIndexedProperty(3).getTestString());
4171     }
4172 
4173     /** Text case for setting properties on inner classes */
4174     public void testGetSetInnerBean() throws Exception {
4175         final BeanWithInnerBean bean = new BeanWithInnerBean();
4176 
4177         PropertyUtils.setProperty(bean, "innerBean.fish(loiterTimer)", "5");
4178         String out = (String) PropertyUtils.getProperty(bean.getInnerBean(), "fish(loiterTimer)");
4179         assertEquals(
4180                 "(1) Inner class property set/get property failed.",
4181                 "5",
4182                 out);
4183 
4184         out = (String) PropertyUtils.getProperty(bean, "innerBean.fish(loiterTimer)");
4185 
4186         assertEquals(
4187                 "(2) Inner class property set/get property failed.",
4188                 "5",
4189                 out);
4190     }
4191 
4192     /** Text case for setting properties on parent */
4193     public void testGetSetParentBean() throws Exception {
4194 
4195         final SonOfAlphaBean bean = new SonOfAlphaBean("Roger");
4196 
4197         final String out = (String) PropertyUtils.getProperty(bean, "name");
4198         assertEquals(
4199                 "(1) Get/Set On Parent.",
4200                 "Roger",
4201                 out);
4202 
4203         PropertyUtils.setProperty(bean, "name", "abcd");
4204         assertEquals(
4205                 "(2) Get/Set On Parent.",
4206                 "abcd",
4207                 bean.getName());
4208     }
4209 
4210     public void testSetNoGetter() throws Exception
4211     {
4212         final BetaBean bean = new BetaBean("Cedric");
4213 
4214         // test standard no getter
4215         bean.setNoGetterProperty("Sigma");
4216         assertEquals("BetaBean test failed", "Sigma", bean.getSecret());
4217 
4218         assertNotNull("Descriptor is null", PropertyUtils.getPropertyDescriptor(bean, "noGetterProperty"));
4219 
4220         BeanUtils.setProperty(bean, "noGetterProperty",  "Omega");
4221         assertEquals("Cannot set no-getter property", "Omega", bean.getSecret());
4222 
4223         // test mapped no getter descriptor
4224         assertNotNull("Map Descriptor is null", PropertyUtils.getPropertyDescriptor(bean, "noGetterMappedProperty"));
4225 
4226         PropertyUtils.setMappedProperty(bean, "noGetterMappedProperty",  "Epsilon", "Epsilon");
4227         assertEquals("Cannot set mapped no-getter property", "MAP:Epsilon", bean.getSecret());
4228     }
4229 
4230     /**
4231      * Test accessing a public sub-bean of a package scope bean
4232      */
4233     public void testSetPublicSubBean_of_PackageBean() {
4234 
4235         final PublicSubBean bean = new PublicSubBean();
4236         bean.setFoo("foo-start");
4237         bean.setBar("bar-start");
4238 
4239         // Set Foo
4240         try {
4241             PropertyUtils.setProperty(bean, "foo", "foo-updated");
4242         } catch (final Throwable t) {
4243             fail("setProperty(foo) threw " + t);
4244         }
4245         assertEquals("foo property", "foo-updated", bean.getFoo());
4246 
4247         // Set Bar
4248         try {
4249             PropertyUtils.setProperty(bean, "bar", "bar-updated");
4250         } catch (final Throwable t) {
4251             fail("setProperty(bar) threw " + t);
4252         }
4253         assertEquals("bar property", "bar-updated", bean.getBar());
4254     }
4255 
4256     /**
4257      * There is an issue in setNestedProperty/getNestedProperty when the
4258      * target bean is a map and the name string requests mapped or indexed
4259      * operations on a field. These are not supported for fields of a Map,
4260      * but it's an easy mistake to make and this test case ensures that an
4261      * appropriate exception is thrown when a user does this.
4262      * <p>
4263      * The problem is with passing strings of form "a(b)" or "a[3]" to
4264      * setNestedProperty or getNestedProperty when the target bean they
4265      * are applied to implements Map. These strings are actually requesting
4266      * "the result of calling mapped method a on the target object with
4267      * a parameter of b" or "the result of calling indexed method a on the
4268      * target object with a parameter of 3". And these requests are not valid
4269      * when the target is a Map as a Map only supports calling get(fieldName)
4270      * or put(fieldName), neither of which can be further indexed with a
4271      * string or an integer.
4272      * <p>
4273      * However it is likely that some users will assume that "a[3]" when applied
4274      * to a map will be equivalent to (map.get("a"))[3] with the appropriate
4275      * typecasting, or for "a(b)" to be equivalent to map.get("a").get("b").
4276      * <p>
4277      * Here we verify that an exception is thrown if the user makes this
4278      * mistake.
4279      */
4280     public void testNestedPropertyKeyOrIndexOnBeanImplementingMap() throws Exception {
4281         final HashMap<String, Object> map = new HashMap<String, Object>();
4282         final HashMap<String, Object> submap = new HashMap<String, Object>();
4283         final BetaBean betaBean1 = new BetaBean("test1");
4284         final BetaBean betaBean2 = new BetaBean("test2");
4285 
4286         // map.put("submap", submap)
4287         PropertyUtils.setNestedProperty(map, "submap", submap);
4288 
4289         // map.get("submap").put("beta1", betaBean1)
4290         PropertyUtils.setNestedProperty(map, "submap.beta1", betaBean1);
4291         assertEquals("Unexpected keys in map", "submap", keysToString(map));
4292         assertEquals("Unexpected keys in submap", "beta1", keysToString(submap));
4293 
4294         try {
4295             // One would expect that the command below would be equivalent to
4296             //   Map m = (Map) map.get("submap");
4297             //   m.put("beta2", betaBean2)
4298             // However this isn't how javabeans property methods work. A map
4299             // only effectively has "simple" properties, even when the
4300             // returned object is a Map or Array.
4301             PropertyUtils.setNestedProperty(map, "submap(beta2)", betaBean2);
4302 
4303             // What, no exception? In that case, setNestedProperties has
4304             // probably just tried to do
4305             //    map.set("submap(beta2)", betaBean2)
4306             // which is almost certainly not what the used expected. This is
4307             // what beanutils 1.5.0 to 1.7.1 did....
4308             fail("Exception not thrown for invalid setNestedProperty syntax");
4309         } catch(final IllegalArgumentException ex) {
4310             // ok, getting an exception was expected. As it is of a generic
4311             // type, let's check the message string to make sure it really
4312             // was caused by the issue we expected.
4313             final int index = ex.getMessage().indexOf(
4314                     "Indexed or mapped properties are not supported");
4315             assertTrue("Unexpected exception message", index>=0);
4316         }
4317 
4318         try {
4319             // One would expect that "submap[3]" would be equivalent to
4320             //   Object[] objects = (Object[]) map.get("submap");
4321             //   return objects[3];
4322             // However this isn't how javabeans property methods work. A map
4323             // only effectively has "simple" properties, even when the
4324             // returned object is a Map or Array.
4325             PropertyUtils.getNestedProperty(map, "submap[3]");
4326 
4327             // What, no exception? In that case, getNestedProperties has
4328             // probably just tried to do
4329             //    map.get("submap[3]")
4330             // which is almost certainly not what the used expected. This is
4331             // what beanutils 1.5.0 to 1.7.1 did....
4332             fail("Exception not thrown for invalid setNestedProperty syntax");
4333         } catch(final IllegalArgumentException ex) {
4334             // ok, getting an exception was expected. As it is of a generic
4335             // type, let's check the message string to make sure it really
4336             // was caused by the issue we expected.
4337             final int index = ex.getMessage().indexOf(
4338                     "Indexed or mapped properties are not supported");
4339             assertTrue("Unexpected exception message", index>=0);
4340         }
4341     }
4342 
4343     /**
4344      * Returns a single string containing all the keys in the map,
4345      * sorted in alphabetical order and separated by ", ".
4346      * <p>
4347      * If there are no keys, an empty string is returned.
4348      */
4349     private String keysToString(final Map<?, ?> map) {
4350         final Object[] mapKeys = map.keySet().toArray();
4351         java.util.Arrays.sort(mapKeys);
4352         final StringBuilder buf = new StringBuilder();
4353         for(int i=0; i<mapKeys.length; ++i) {
4354             if (i != 0) {
4355                 buf.append(", ");
4356             }
4357             buf.append(mapKeys[i]);
4358         }
4359         return buf.toString();
4360     }
4361 
4362     /**
4363      * This tests to see that classes that implement Map always have their
4364      * custom properties ignored.
4365      * <p>
4366      * Note that this behaviour has changed several times over past releases
4367      * of beanutils, breaking backwards compatibility each time. Here's hoping
4368      * that the current 1.7.1 release is the last time this behaviour changes!
4369      */
4370     public void testMapExtensionDefault() throws Exception {
4371         final ExtendMapBean bean = new ExtendMapBean();
4372 
4373         // setting property direct should work, and not affect map
4374         bean.setUnusuallyNamedProperty("bean value");
4375         assertEquals("Set property direct failed", "bean value", bean.getUnusuallyNamedProperty());
4376         assertNull("Get on unset map property failed",
4377                 PropertyUtils.getNestedProperty(bean, "unusuallyNamedProperty"));
4378 
4379         // setting simple property should call the setter method only, and not
4380         // affect the map.
4381         PropertyUtils.setSimpleProperty(bean, "unusuallyNamedProperty", "new value");
4382         assertEquals("Set property on map failed (1)", "new value", bean.getUnusuallyNamedProperty());
4383         assertNull("Get on unset map property failed",
4384                 PropertyUtils.getNestedProperty(bean, "unusuallyNamedProperty"));
4385 
4386         // setting via setNestedProperty should affect the map only, and not
4387         // call the setter method.
4388         PropertyUtils.setProperty(bean, "unusuallyNamedProperty", "next value");
4389         assertEquals(
4390                 "setNestedProperty on map not visible to getNestedProperty",
4391                 "next value",
4392                 PropertyUtils.getNestedProperty(bean, "unusuallyNamedProperty"));
4393         assertEquals(
4394             "Set nested property on map unexpected affected simple property",
4395             "new value",
4396             bean.getUnusuallyNamedProperty());
4397     }
4398 
4399     /**
4400      * This tests to see that it is possible to subclass PropertyUtilsBean
4401      * and change the behaviour of setNestedProperty/getNestedProperty when
4402      * dealing with objects that implement Map.
4403      */
4404     public void testMapExtensionCustom() throws Exception {
4405         final PropsFirstPropertyUtilsBean utilsBean = new PropsFirstPropertyUtilsBean();
4406         final ExtendMapBean bean = new ExtendMapBean();
4407 
4408         // hardly worth testing this, really :-)
4409         bean.setUnusuallyNamedProperty("bean value");
4410         assertEquals("Set property direct failed", "bean value", bean.getUnusuallyNamedProperty());
4411 
4412         // setSimpleProperty should affect the simple property
4413         utilsBean.setSimpleProperty(bean, "unusuallyNamedProperty", "new value");
4414         assertEquals("Set property on map failed (1)", "new value", bean.getUnusuallyNamedProperty());
4415 
4416         // setNestedProperty with setter should affect the simple property
4417         // getNestedProperty with getter should obtain the simple property
4418         utilsBean.setProperty(bean, "unusuallyNamedProperty", "next value");
4419         assertEquals("Set property on map failed (2)", "next value", bean.getUnusuallyNamedProperty());
4420         assertEquals("setNestedProperty on non-simple property failed",
4421                 "next value",
4422                 utilsBean.getNestedProperty(bean, "unusuallyNamedProperty"));
4423 
4424         // setting property without setter should update the map
4425         // getting property without setter should fetch from the map
4426         utilsBean.setProperty(bean, "mapProperty", "value1");
4427         assertEquals("setNestedProperty on non-simple property failed",
4428                 "value1", utilsBean.getNestedProperty(bean, "mapProperty"));
4429 
4430         final HashMap<String, Object> myMap = new HashMap<String, Object>();
4431         myMap.put("thebean", bean);
4432         utilsBean.getNestedProperty(myMap, "thebean.mapitem");
4433         utilsBean.getNestedProperty(myMap, "thebean(mapitem)");
4434     }
4435 
4436     /**
4437      * Test {@link PropertyUtilsBean}'s invoke method throwing an IllegalArgumentException
4438      * and check that the "cause" has been properly initialized for JDK 1.4+
4439      * See BEANUTILS-266 for changes and reason for test
4440      */
4441     public void testExceptionFromInvoke() throws Exception {
4442         if (BeanUtilsTestCase.isPre14JVM()) {
4443             return;
4444         }
4445         try {
4446             PropertyUtils.setSimpleProperty(bean, "intProperty","XXX");
4447         } catch(final IllegalArgumentException t) {
4448             final Throwable cause = (Throwable)PropertyUtils.getProperty(t, "cause");
4449             assertNotNull("Cause not found", cause);
4450             assertTrue("Expected cause to be IllegalArgumentException, but was: " + cause.getClass(),
4451                     cause instanceof IllegalArgumentException);
4452             // JDK 1.6 doesn't have "argument type mismatch" message
4453             // assertEquals("Check error message", "argument type mismatch", cause.getMessage());
4454         } catch(final Throwable t) {
4455             fail("Expected IllegalArgumentException, but threw " + t);
4456         }
4457     }
4458 
4459     /**
4460      * Tests whether the default introspection mechanism can be replaced by a
4461      * custom BeanIntrospector.
4462      */
4463     public void testCustomIntrospection() {
4464         final PropertyDescriptor[] desc1 = PropertyUtils
4465                 .getPropertyDescriptors(AlphaBean.class);
4466         PropertyDescriptor nameDescriptor = findNameDescriptor(desc1);
4467         assertNotNull("No write method", nameDescriptor.getWriteMethod());
4468 
4469         final BeanIntrospector bi = new BeanIntrospector() {
4470             // Only produce read-only property descriptors
4471             public void introspect(final IntrospectionContext icontext)
4472                     throws IntrospectionException {
4473                 final Set<String> names = icontext.propertyNames();
4474                 final PropertyDescriptor[] newDescs = new PropertyDescriptor[names
4475                         .size()];
4476                 int idx = 0;
4477                 for (final Iterator<String> it = names.iterator(); it.hasNext(); idx++) {
4478                     final String propName = it.next();
4479                     final PropertyDescriptor pd = icontext
4480                             .getPropertyDescriptor(propName);
4481                     newDescs[idx] = new PropertyDescriptor(pd.getName(),
4482                             pd.getReadMethod(), null);
4483                 }
4484                 icontext.addPropertyDescriptors(newDescs);
4485             }
4486         };
4487         PropertyUtils.clearDescriptors();
4488         PropertyUtils.addBeanIntrospector(bi);
4489         final PropertyDescriptor[] desc2 = PropertyUtils
4490                 .getPropertyDescriptors(AlphaBean.class);
4491         assertEquals("Different number of properties", desc1.length,
4492                 desc2.length);
4493         nameDescriptor = findNameDescriptor(desc2);
4494         assertNull("Got a write method", nameDescriptor.getWriteMethod());
4495         PropertyUtils.removeBeanIntrospector(bi);
4496     }
4497 
4498     /**
4499      * Finds the descriptor of the name property.
4500      *
4501      * @param desc the array with descriptors
4502      * @return the found descriptor or null
4503      */
4504     private static PropertyDescriptor findNameDescriptor(
4505             final PropertyDescriptor[] desc) {
4506         for (PropertyDescriptor element : desc) {
4507             if (element.getName().equals("name")) {
4508                 return element;
4509             }
4510         }
4511         return null;
4512     }
4513 
4514     /**
4515      * Tests whether exceptions during custom introspection are handled.
4516      */
4517     public void testCustomIntrospectionEx() {
4518         final BeanIntrospector bi = new BeanIntrospector() {
4519             public void introspect(final IntrospectionContext icontext)
4520                     throws IntrospectionException {
4521                 throw new IntrospectionException("TestException");
4522             }
4523         };
4524         PropertyUtils.clearDescriptors();
4525         PropertyUtils.addBeanIntrospector(bi);
4526         final PropertyDescriptor[] desc = PropertyUtils
4527                 .getPropertyDescriptors(AlphaBean.class);
4528         assertNotNull("Introspection did not work", findNameDescriptor(desc));
4529         PropertyUtils.removeBeanIntrospector(bi);
4530     }
4531 
4532     /**
4533      * Tests whether a BeanIntrospector can be removed.
4534      */
4535     public void testRemoveBeanIntrospector() {
4536         assertTrue(
4537                 "Wrong result",
4538                 PropertyUtils
4539                         .removeBeanIntrospector(DefaultBeanIntrospector.INSTANCE));
4540         final PropertyDescriptor[] desc = PropertyUtils
4541                 .getPropertyDescriptors(AlphaBean.class);
4542         assertEquals("Got descriptors", 0, desc.length);
4543         PropertyUtils.addBeanIntrospector(DefaultBeanIntrospector.INSTANCE);
4544     }
4545 
4546     /**
4547      * Tries to add a null BeanIntrospector.
4548      */
4549     public void testAddBeanIntrospectorNull() {
4550         try {
4551             PropertyUtils.addBeanIntrospector(null);
4552             fail("Could add null BeanIntrospector!");
4553         } catch (final IllegalArgumentException iex) {
4554             // ok
4555         }
4556     }
4557 
4558     /**
4559      * Tests whether a reset of the registered BeanIntrospectors can be performed.
4560      */
4561     public void testResetBeanIntrospectors() {
4562         assertTrue("Wrong result",
4563                 PropertyUtils.removeBeanIntrospector(DefaultBeanIntrospector.INSTANCE));
4564         PropertyUtils.resetBeanIntrospectors();
4565         final PropertyDescriptor[] desc = PropertyUtils.getPropertyDescriptors(AlphaBean.class);
4566         assertTrue("Got no descriptors", desc.length > 0);
4567     }
4568 }