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