View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://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  package org.apache.commons.beanutils2;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  
27  import java.util.ArrayList;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.junit.jupiter.api.AfterEach;
33  import org.junit.jupiter.api.BeforeEach;
34  import org.junit.jupiter.api.Test;
35  
36  /**
37   * Test case for BeanUtils when the underlying bean is actually a DynaBean.
38   */
39  public class DynaBeanUtilsTest {
40  
41      /**
42       * Create and return a {@code DynaClass} instance for our test {@code DynaBean}.
43       */
44      protected static DynaClass createDynaClass() {
45  
46          final int[] intArray = {};
47          final String[] stringArray = {};
48  
49          return new BasicDynaClass("TestDynaClass", null, new DynaProperty[] { new DynaProperty("booleanProperty", Boolean.TYPE),
50                  new DynaProperty("booleanSecond", Boolean.TYPE), new DynaProperty("byteProperty", Byte.TYPE), new DynaProperty("doubleProperty", Double.TYPE),
51                  new DynaProperty("dupProperty", stringArray.getClass()), new DynaProperty("floatProperty", Float.TYPE),
52                  new DynaProperty("intArray", intArray.getClass()), new DynaProperty("intIndexed", intArray.getClass()),
53                  new DynaProperty("intProperty", Integer.TYPE), new DynaProperty("listIndexed", List.class), new DynaProperty("longProperty", Long.TYPE),
54                  new DynaProperty("mapProperty", Map.class), new DynaProperty("mappedProperty", Map.class), new DynaProperty("mappedIntProperty", Map.class),
55                  new DynaProperty("nested", TestBean.class), new DynaProperty("nullProperty", String.class), new DynaProperty("shortProperty", Short.TYPE),
56                  new DynaProperty("stringArray", stringArray.getClass()), new DynaProperty("stringIndexed", stringArray.getClass()),
57                  new DynaProperty("stringProperty", String.class), });
58  
59      }
60  
61      /**
62       * The basic test bean for each test.
63       */
64      protected DynaBean bean;
65  
66      /**
67       * The nested bean pointed at by the "nested" property.
68       */
69      protected TestBean nested;
70  
71      /**
72       * The set of properties that should be described.
73       */
74      protected String[] describes = { "booleanProperty", "booleanSecond", "byteProperty", "doubleProperty", "dupProperty", "floatProperty", "intArray",
75              "intIndexed", "intProperty", "listIndexed", "longProperty", "mapProperty", "mappedProperty", "mappedIntProperty", "nested", "nullProperty",
76              // "readOnlyProperty",
77              "shortProperty", "stringArray", "stringIndexed", "stringProperty" };
78  
79      // Ensure that the nested intArray matches the specified values
80      protected void checkIntArray(final int[] actual, final int[] expected) {
81          assertNotNull(actual, "actual array not null");
82          assertEquals(expected.length, actual.length, "actual array length");
83          for (int i = 0; i < actual.length; i++) {
84              assertEquals(expected[i], actual[i], "actual array value[" + i + "]");
85          }
86      }
87  
88      // Ensure that the actual Map matches the expected Map
89      protected void checkMap(final Map<?, ?> actual, final Map<?, ?> expected) {
90          assertNotNull(actual, "actual map not null");
91          assertEquals(expected.size(), actual.size(), "actual map size");
92          for (final Object key : expected.keySet()) {
93              assertEquals(expected.get(key), actual.get(key), "actual map value(" + key + ")");
94          }
95      }
96  
97      /**
98       * Sets up instance variables required by this test case.
99       */
100     @BeforeEach
101     public void setUp() throws Exception {
102 
103         ConvertUtils.deregister();
104 
105         // Instantiate a new DynaBean instance
106         final DynaClass dynaClass = createDynaClass();
107         bean = dynaClass.newInstance();
108 
109         // Initialize the DynaBean's property values (like TestBean)
110         bean.set("booleanProperty", Boolean.valueOf(true));
111         bean.set("booleanSecond", Boolean.valueOf(true));
112         bean.set("byteProperty", Byte.valueOf((byte) 121));
113         bean.set("doubleProperty", Double.valueOf(321.0));
114         bean.set("floatProperty", Float.valueOf((float) 123.0));
115         final String[] dupProperty = { "Dup 0", "Dup 1", "Dup 2", "Dup 3", "Dup 4" };
116         bean.set("dupProperty", dupProperty);
117         final int[] intArray = { 0, 10, 20, 30, 40 };
118         bean.set("intArray", intArray);
119         final int[] intIndexed = { 0, 10, 20, 30, 40 };
120         bean.set("intIndexed", intIndexed);
121         bean.set("intProperty", Integer.valueOf(123));
122         final List<String> listIndexed = new ArrayList<>();
123         listIndexed.add("String 0");
124         listIndexed.add("String 1");
125         listIndexed.add("String 2");
126         listIndexed.add("String 3");
127         listIndexed.add("String 4");
128         bean.set("listIndexed", listIndexed);
129         bean.set("longProperty", Long.valueOf(321));
130         final HashMap<String, Object> mapProperty = new HashMap<>();
131         mapProperty.put("First Key", "First Value");
132         mapProperty.put("Second Key", "Second Value");
133         bean.set("mapProperty", mapProperty);
134         final HashMap<String, Object> mappedProperty = new HashMap<>();
135         mappedProperty.put("First Key", "First Value");
136         mappedProperty.put("Second Key", "Second Value");
137         bean.set("mappedProperty", mappedProperty);
138         final HashMap<String, Integer> mappedIntProperty = new HashMap<>();
139         mappedIntProperty.put("One", Integer.valueOf(1));
140         mappedIntProperty.put("Two", Integer.valueOf(2));
141         bean.set("mappedIntProperty", mappedIntProperty);
142         nested = new TestBean();
143         bean.set("nested", nested);
144         // Property "nullProperty" is not initialized, so it should return null
145         bean.set("shortProperty", Short.valueOf((short) 987));
146         final String[] stringArray = { "String 0", "String 1", "String 2", "String 3", "String 4" };
147         bean.set("stringArray", stringArray);
148         final String[] stringIndexed = { "String 0", "String 1", "String 2", "String 3", "String 4" };
149         bean.set("stringIndexed", stringIndexed);
150         bean.set("stringProperty", "This is a string");
151 
152     }
153 
154     /**
155      * Tear down instance variables required by this test case.
156      */
157     @AfterEach
158     public void tearDown() {
159 
160         bean = null;
161         nested = null;
162 
163     }
164 
165     /**
166      * Test the cloneBean() method from a DynaBean.
167      */
168     @Test
169     public void testCloneDynaBean() throws Exception {
170 
171         // Set up an origin bean with customized properties
172         final DynaClass dynaClass = DynaBeanUtilsTest.createDynaClass();
173         final DynaBean orig = dynaClass.newInstance();
174         orig.set("booleanProperty", Boolean.FALSE);
175         orig.set("byteProperty", Byte.valueOf((byte) 111));
176         orig.set("doubleProperty", Double.valueOf(333.33));
177         orig.set("dupProperty", new String[] { "New 0", "New 1", "New 2" });
178         orig.set("intArray", new int[] { 100, 200, 300 });
179         orig.set("intProperty", Integer.valueOf(333));
180         orig.set("longProperty", Long.valueOf(3333));
181         orig.set("shortProperty", Short.valueOf((short) 33));
182         orig.set("stringArray", new String[] { "New 0", "New 1" });
183         orig.set("stringProperty", "Custom string");
184 
185         // Copy the origin bean to our destination test bean
186         final DynaBean clonedBean = (DynaBean) BeanUtils.cloneBean(orig);
187 
188         // Validate the results for scalar properties
189         assertEquals(false, ((Boolean) clonedBean.get("booleanProperty")).booleanValue(), "Cloned boolean property");
190         assertEquals((byte) 111, ((Byte) clonedBean.get("byteProperty")).byteValue(), "Cloned byte property");
191         assertEquals(333.33, ((Double) clonedBean.get("doubleProperty")).doubleValue(), 0.005, "Cloned double property");
192         assertEquals(333, ((Integer) clonedBean.get("intProperty")).intValue(), "Cloned int property");
193         assertEquals(3333, ((Long) clonedBean.get("longProperty")).longValue(), "Cloned long property");
194         assertEquals((short) 33, ((Short) clonedBean.get("shortProperty")).shortValue(), "Cloned short property");
195         assertEquals("Custom string", (String) clonedBean.get("stringProperty"), "Cloned string property");
196 
197         // Validate the results for array properties
198         final String[] dupProperty = (String[]) clonedBean.get("dupProperty");
199         assertNotNull(dupProperty, "dupProperty present");
200         assertEquals(3, dupProperty.length, "dupProperty length");
201         assertEquals("New 0", dupProperty[0], "dupProperty[0]");
202         assertEquals("New 1", dupProperty[1], "dupProperty[1]");
203         assertEquals("New 2", dupProperty[2], "dupProperty[2]");
204         final int[] intArray = (int[]) clonedBean.get("intArray");
205         assertNotNull(intArray, "intArray present");
206         assertEquals(3, intArray.length, "intArray length");
207         assertEquals(100, intArray[0], "intArray[0]");
208         assertEquals(200, intArray[1], "intArray[1]");
209         assertEquals(300, intArray[2], "intArray[2]");
210         final String[] stringArray = (String[]) clonedBean.get("stringArray");
211         assertNotNull(stringArray, "stringArray present");
212         assertEquals(2, stringArray.length, "stringArray length");
213         assertEquals("New 0", stringArray[0], "stringArray[0]");
214         assertEquals("New 1", stringArray[1], "stringArray[1]");
215 
216     }
217 
218     /**
219      * Test the copyProperties() method from a DynaBean.
220      */
221     @Test
222     public void testCopyPropertiesDynaBean() throws Exception {
223 
224         // Set up an origin bean with customized properties
225         final DynaClass dynaClass = DynaBeanUtilsTest.createDynaClass();
226         final DynaBean orig = dynaClass.newInstance();
227         orig.set("booleanProperty", Boolean.FALSE);
228         orig.set("byteProperty", Byte.valueOf((byte) 111));
229         orig.set("doubleProperty", Double.valueOf(333.33));
230         orig.set("dupProperty", new String[] { "New 0", "New 1", "New 2" });
231         orig.set("intArray", new int[] { 100, 200, 300 });
232         orig.set("intProperty", Integer.valueOf(333));
233         orig.set("longProperty", Long.valueOf(3333));
234         orig.set("shortProperty", Short.valueOf((short) 33));
235         orig.set("stringArray", new String[] { "New 0", "New 1" });
236         orig.set("stringProperty", "Custom string");
237 
238         // Copy the origin bean to our destination test bean
239         BeanUtils.copyProperties(bean, orig);
240 
241         // Validate the results for scalar properties
242         assertEquals(false, ((Boolean) bean.get("booleanProperty")).booleanValue(), "Copied boolean property");
243         assertEquals((byte) 111, ((Byte) bean.get("byteProperty")).byteValue(), "Copied byte property");
244         assertEquals(333.33, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005, "Copied double property");
245         assertEquals(333, ((Integer) bean.get("intProperty")).intValue(), "Copied int property");
246         assertEquals(3333, ((Long) bean.get("longProperty")).longValue(), "Copied long property");
247         assertEquals((short) 33, ((Short) bean.get("shortProperty")).shortValue(), "Copied short property");
248         assertEquals("Custom string", (String) bean.get("stringProperty"), "Copied string property");
249 
250         // Validate the results for array properties
251         final String[] dupProperty = (String[]) bean.get("dupProperty");
252         assertNotNull(dupProperty, "dupProperty present");
253         assertEquals(3, dupProperty.length, "dupProperty length");
254         assertEquals("New 0", dupProperty[0], "dupProperty[0]");
255         assertEquals("New 1", dupProperty[1], "dupProperty[1]");
256         assertEquals("New 2", dupProperty[2], "dupProperty[2]");
257         final int[] intArray = (int[]) bean.get("intArray");
258         assertNotNull(intArray, "intArray present");
259         assertEquals(3, intArray.length, "intArray length");
260         assertEquals(100, intArray[0], "intArray[0]");
261         assertEquals(200, intArray[1], "intArray[1]");
262         assertEquals(300, intArray[2], "intArray[2]");
263         final String[] stringArray = (String[]) bean.get("stringArray");
264         assertNotNull(stringArray, "stringArray present");
265         assertEquals(2, stringArray.length, "stringArray length");
266         assertEquals("New 0", stringArray[0], "stringArray[0]");
267         assertEquals("New 1", stringArray[1], "stringArray[1]");
268 
269     }
270 
271     /**
272      * Test copyProperties() when the origin is a {@code Map}.
273      */
274     @Test
275     public void testCopyPropertiesMap() throws Exception {
276 
277         final Map<String, Object> map = new HashMap<>();
278         map.put("booleanProperty", "false");
279         map.put("byteProperty", "111");
280         map.put("doubleProperty", "333.0");
281         map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
282         map.put("floatProperty", "222.0");
283         map.put("intArray", new String[] { "0", "100", "200" });
284         map.put("intProperty", "111");
285         map.put("longProperty", "444");
286         map.put("shortProperty", "555");
287         map.put("stringProperty", "New String Property");
288 
289         BeanUtils.copyProperties(bean, map);
290 
291         // Scalar properties
292         assertEquals(false, ((Boolean) bean.get("booleanProperty")).booleanValue(), "booleanProperty");
293         assertEquals((byte) 111, ((Byte) bean.get("byteProperty")).byteValue(), "byteProperty");
294         assertEquals(333.0, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005, "doubleProperty");
295         assertEquals((float) 222.0, ((Float) bean.get("floatProperty")).floatValue(), (float) 0.005, "floatProperty");
296         assertEquals(111, ((Integer) bean.get("intProperty")).intValue(), "intProperty");
297         assertEquals(444, ((Long) bean.get("longProperty")).longValue(), "longProperty");
298         assertEquals((short) 555, ((Short) bean.get("shortProperty")).shortValue(), "shortProperty");
299         assertEquals("New String Property", (String) bean.get("stringProperty"), "stringProperty");
300 
301         // Indexed Properties
302         final String[] dupProperty = (String[]) bean.get("dupProperty");
303         assertNotNull(dupProperty, "dupProperty present");
304         assertEquals(3, dupProperty.length, "dupProperty length");
305         assertEquals("New 0", dupProperty[0], "dupProperty[0]");
306         assertEquals("New 1", dupProperty[1], "dupProperty[1]");
307         assertEquals("New 2", dupProperty[2], "dupProperty[2]");
308         final int[] intArray = (int[]) bean.get("intArray");
309         assertNotNull(intArray, "intArray present");
310         assertEquals(3, intArray.length, "intArray length");
311         assertEquals(0, intArray[0], "intArray[0]");
312         assertEquals(100, intArray[1], "intArray[1]");
313         assertEquals(200, intArray[2], "intArray[2]");
314 
315     }
316 
317     /**
318      * Test the copyProperties() method from a standard JavaBean.
319      */
320     @Test
321     public void testCopyPropertiesStandard() throws Exception {
322 
323         // Set up an origin bean with customized properties
324         final TestBean orig = new TestBean();
325         orig.setBooleanProperty(false);
326         orig.setByteProperty((byte) 111);
327         orig.setDoubleProperty(333.33);
328         orig.setDupProperty(new String[] { "New 0", "New 1", "New 2" });
329         orig.setIntArray(new int[] { 100, 200, 300 });
330         orig.setIntProperty(333);
331         orig.setLongProperty(3333);
332         orig.setShortProperty((short) 33);
333         orig.setStringArray(new String[] { "New 0", "New 1" });
334         orig.setStringProperty("Custom string");
335 
336         // Copy the origin bean to our destination test bean
337         BeanUtils.copyProperties(bean, orig);
338 
339         // Validate the results for scalar properties
340         assertEquals(false, ((Boolean) bean.get("booleanProperty")).booleanValue(), "Copied boolean property");
341         assertEquals((byte) 111, ((Byte) bean.get("byteProperty")).byteValue(), "Copied byte property");
342         assertEquals(333.33, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005, "Copied double property");
343         assertEquals(333, ((Integer) bean.get("intProperty")).intValue(), "Copied int property");
344         assertEquals(3333, ((Long) bean.get("longProperty")).longValue(), "Copied long property");
345         assertEquals((short) 33, ((Short) bean.get("shortProperty")).shortValue(), "Copied short property");
346         assertEquals("Custom string", (String) bean.get("stringProperty"), "Copied string property");
347 
348         // Validate the results for array properties
349         final String[] dupProperty = (String[]) bean.get("dupProperty");
350         assertNotNull(dupProperty, "dupProperty present");
351         assertEquals(3, dupProperty.length, "dupProperty length");
352         assertEquals("New 0", dupProperty[0], "dupProperty[0]");
353         assertEquals("New 1", dupProperty[1], "dupProperty[1]");
354         assertEquals("New 2", dupProperty[2], "dupProperty[2]");
355         final int[] intArray = (int[]) bean.get("intArray");
356         assertNotNull(intArray, "intArray present");
357         assertEquals(3, intArray.length, "intArray length");
358         assertEquals(100, intArray[0], "intArray[0]");
359         assertEquals(200, intArray[1], "intArray[1]");
360         assertEquals(300, intArray[2], "intArray[2]");
361         final String[] stringArray = (String[]) bean.get("stringArray");
362         assertNotNull(stringArray, "stringArray present");
363         assertEquals(2, stringArray.length, "stringArray length");
364         assertEquals("New 0", stringArray[0], "stringArray[0]");
365         assertEquals("New 1", stringArray[1], "stringArray[1]");
366 
367     }
368 
369     /**
370      * Test narrowing and widening conversions on byte.
371      */
372     @Test
373     public void testCopyPropertyByte() throws Exception {
374 
375         BeanUtils.setProperty(bean, "byteProperty", Byte.valueOf((byte) 123));
376         assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
377         /*
378          * BeanUtils.setProperty(bean, "byteProperty", new Double((double) 123)); assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
379          * BeanUtils.setProperty(bean, "byteProperty", new Float((float) 123)); assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
380          */
381         BeanUtils.setProperty(bean, "byteProperty", Integer.valueOf(123));
382         assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
383         BeanUtils.setProperty(bean, "byteProperty", Long.valueOf(123));
384         assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
385         BeanUtils.setProperty(bean, "byteProperty", Short.valueOf((short) 123));
386         assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
387 
388     }
389 
390     /**
391      * Test narrowing and widening conversions on double.
392      */
393     @Test
394     public void testCopyPropertyDouble() throws Exception {
395 
396         BeanUtils.setProperty(bean, "doubleProperty", Byte.valueOf((byte) 123));
397         assertEquals(123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
398         BeanUtils.setProperty(bean, "doubleProperty", Double.valueOf(123));
399         assertEquals(123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
400         BeanUtils.setProperty(bean, "doubleProperty", Float.valueOf(123));
401         assertEquals(123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
402         BeanUtils.setProperty(bean, "doubleProperty", Integer.valueOf(123));
403         assertEquals(123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
404         BeanUtils.setProperty(bean, "doubleProperty", Long.valueOf(123));
405         assertEquals(123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
406         BeanUtils.setProperty(bean, "doubleProperty", Short.valueOf((short) 123));
407         assertEquals(123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
408 
409     }
410 
411     /**
412      * Test narrowing and widening conversions on float.
413      */
414     @Test
415     public void testCopyPropertyFloat() throws Exception {
416 
417         BeanUtils.setProperty(bean, "floatProperty", Byte.valueOf((byte) 123));
418         assertEquals(123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
419         BeanUtils.setProperty(bean, "floatProperty", Double.valueOf(123));
420         assertEquals(123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
421         BeanUtils.setProperty(bean, "floatProperty", Float.valueOf(123));
422         assertEquals(123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
423         BeanUtils.setProperty(bean, "floatProperty", Integer.valueOf(123));
424         assertEquals(123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
425         BeanUtils.setProperty(bean, "floatProperty", Long.valueOf(123));
426         assertEquals(123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
427         BeanUtils.setProperty(bean, "floatProperty", Short.valueOf((short) 123));
428         assertEquals(123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
429 
430     }
431 
432     /**
433      * Test narrowing and widening conversions on int.
434      */
435     @Test
436     public void testCopyPropertyInteger() throws Exception {
437 
438         BeanUtils.setProperty(bean, "longProperty", Byte.valueOf((byte) 123));
439         assertEquals(123, ((Integer) bean.get("intProperty")).intValue());
440         /*
441          * BeanUtils.setProperty(bean, "longProperty", new Double((double) 123)); assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
442          * BeanUtils.setProperty(bean, "longProperty", new Float((float) 123)); assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
443          */
444         BeanUtils.setProperty(bean, "longProperty", Integer.valueOf(123));
445         assertEquals(123, ((Integer) bean.get("intProperty")).intValue());
446         BeanUtils.setProperty(bean, "longProperty", Long.valueOf(123));
447         assertEquals(123, ((Integer) bean.get("intProperty")).intValue());
448         BeanUtils.setProperty(bean, "longProperty", Short.valueOf((short) 123));
449         assertEquals(123, ((Integer) bean.get("intProperty")).intValue());
450 
451     }
452 
453     /**
454      * Test narrowing and widening conversions on long.
455      */
456     @Test
457     public void testCopyPropertyLong() throws Exception {
458 
459         BeanUtils.setProperty(bean, "longProperty", Byte.valueOf((byte) 123));
460         assertEquals(123, ((Long) bean.get("longProperty")).longValue());
461         /*
462          * BeanUtils.setProperty(bean, "longProperty", new Double((double) 123)); assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
463          * BeanUtils.setProperty(bean, "longProperty", new Float((float) 123)); assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
464          */
465         BeanUtils.setProperty(bean, "longProperty", Integer.valueOf(123));
466         assertEquals(123, ((Long) bean.get("longProperty")).longValue());
467         BeanUtils.setProperty(bean, "longProperty", Long.valueOf(123));
468         assertEquals(123, ((Long) bean.get("longProperty")).longValue());
469         BeanUtils.setProperty(bean, "longProperty", Short.valueOf((short) 123));
470         assertEquals(123, ((Long) bean.get("longProperty")).longValue());
471 
472     }
473 
474     /**
475      * Test copying a property using a nested indexed array expression, with and without conversions.
476      */
477     @Test
478     public void testCopyPropertyNestedIndexedArray() throws Exception {
479 
480         final int[] origArray = { 0, 10, 20, 30, 40 };
481         final int[] intArray = { 0, 0, 0 };
482         ((TestBean) bean.get("nested")).setIntArray(intArray);
483         final int[] intChanged = { 0, 0, 0 };
484 
485         // No conversion required
486         BeanUtils.copyProperty(bean, "nested.intArray[1]", Integer.valueOf(1));
487         checkIntArray((int[]) bean.get("intArray"), origArray);
488         intChanged[1] = 1;
489         checkIntArray(((TestBean) bean.get("nested")).getIntArray(), intChanged);
490 
491         // Widening conversion required
492         BeanUtils.copyProperty(bean, "nested.intArray[1]", Byte.valueOf((byte) 2));
493         checkIntArray((int[]) bean.get("intArray"), origArray);
494         intChanged[1] = 2;
495         checkIntArray(((TestBean) bean.get("nested")).getIntArray(), intChanged);
496 
497         // Narrowing conversion required
498         BeanUtils.copyProperty(bean, "nested.intArray[1]", Long.valueOf(3));
499         checkIntArray((int[]) bean.get("intArray"), origArray);
500         intChanged[1] = 3;
501         checkIntArray(((TestBean) bean.get("nested")).getIntArray(), intChanged);
502 
503         // String conversion required
504         BeanUtils.copyProperty(bean, "nested.intArray[1]", "4");
505         checkIntArray((int[]) bean.get("intArray"), origArray);
506         intChanged[1] = 4;
507         checkIntArray(((TestBean) bean.get("nested")).getIntArray(), intChanged);
508 
509     }
510 
511     /**
512      * Test copying a property using a nested mapped map property.
513      */
514     @Test
515     public void testCopyPropertyNestedMappedMap() throws Exception {
516 
517         final Map<String, Object> origMap = new HashMap<>();
518         origMap.put("First Key", "First Value");
519         origMap.put("Second Key", "Second Value");
520         final Map<String, Object> changedMap = new HashMap<>();
521         changedMap.put("First Key", "First Value");
522         changedMap.put("Second Key", "Second Value");
523 
524         // No conversion required
525         BeanUtils.copyProperty(bean, "nested.mapProperty(Second Key)", "New Second Value");
526         checkMap((Map<?, ?>) bean.get("mapProperty"), origMap);
527         changedMap.put("Second Key", "New Second Value");
528         checkMap(((TestBean) bean.get("nested")).getMapProperty(), changedMap);
529 
530     }
531 
532     /**
533      * Test copying a property using a nested simple expression, with and without conversions.
534      */
535     @Test
536     public void testCopyPropertyNestedSimple() throws Exception {
537 
538         bean.set("intProperty", Integer.valueOf(0));
539         nested.setIntProperty(0);
540 
541         // No conversion required
542         BeanUtils.copyProperty(bean, "nested.intProperty", Integer.valueOf(1));
543         assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
544         assertEquals(1, nested.getIntProperty());
545 
546         // Widening conversion required
547         BeanUtils.copyProperty(bean, "nested.intProperty", Byte.valueOf((byte) 2));
548         assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
549         assertEquals(2, nested.getIntProperty());
550 
551         // Narrowing conversion required
552         BeanUtils.copyProperty(bean, "nested.intProperty", Long.valueOf(3));
553         assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
554         assertEquals(3, nested.getIntProperty());
555 
556         // String conversion required
557         BeanUtils.copyProperty(bean, "nested.intProperty", "4");
558         assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
559         assertEquals(4, nested.getIntProperty());
560 
561     }
562 
563     /**
564      * Test copying a null property value.
565      */
566     @Test
567     public void testCopyPropertyNull() throws Exception {
568 
569         bean.set("nullProperty", "non-null value");
570         BeanUtils.copyProperty(bean, "nullProperty", null);
571         assertNull(bean.get("nullProperty"), "nullProperty is null");
572 
573     }
574 
575     /**
576      * Test narrowing and widening conversions on short.
577      */
578     @Test
579     public void testCopyPropertyShort() throws Exception {
580 
581         BeanUtils.setProperty(bean, "shortProperty", Byte.valueOf((byte) 123));
582         assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
583         /*
584          * BeanUtils.setProperty(bean, "shortProperty", new Double((double) 123)); assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
585          * BeanUtils.setProperty(bean, "shortProperty", new Float((float) 123)); assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
586          */
587         BeanUtils.setProperty(bean, "shortProperty", Integer.valueOf(123));
588         assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
589         BeanUtils.setProperty(bean, "shortProperty", Long.valueOf(123));
590         assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
591         BeanUtils.setProperty(bean, "shortProperty", Short.valueOf((short) 123));
592         assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
593 
594     }
595 
596     /**
597      * Test the describe() method.
598      */
599     @Test
600     public void testDescribe() throws Exception {
601 
602         final Map<String, Object> map = PropertyUtils.describe(bean);
603 
604         // Verify existence of all the properties that should be present
605         for (final String describe : describes) {
606             assertTrue(map.containsKey(describe), "Property '" + describe + "' is present");
607         }
608         assertFalse(map.containsKey("writeOnlyProperty"), "Property 'writeOnlyProperty' is not present");
609 
610         // Verify the values of scalar properties
611         assertEquals(Boolean.TRUE, map.get("booleanProperty"), "Value of 'booleanProperty'");
612         assertEquals(Byte.valueOf((byte) 121), map.get("byteProperty"), "Value of 'byteProperty'");
613         assertEquals(Double.valueOf(321.0), map.get("doubleProperty"), "Value of 'doubleProperty'");
614         assertEquals(Float.valueOf((float) 123.0), map.get("floatProperty"), "Value of 'floatProperty'");
615         assertEquals(Integer.valueOf(123), map.get("intProperty"), "Value of 'intProperty'");
616         assertEquals(Long.valueOf(321), map.get("longProperty"), "Value of 'longProperty'");
617         assertEquals(Short.valueOf((short) 987), map.get("shortProperty"), "Value of 'shortProperty'");
618         assertEquals("This is a string", (String) map.get("stringProperty"), "Value of 'stringProperty'");
619 
620     }
621 
622     /**
623      * tests the string and int arrays of TestBean
624      */
625     @Test
626     public void testGetArrayProperty() throws Exception {
627         String[] arr = BeanUtils.getArrayProperty(bean, "stringArray");
628         final String[] comp = (String[]) bean.get("stringArray");
629 
630         assertEquals(comp.length, arr.length, "String array length = " + comp.length);
631 
632         arr = BeanUtils.getArrayProperty(bean, "intArray");
633         final int[] iarr = (int[]) bean.get("intArray");
634 
635         assertEquals(iarr.length, arr.length, "String array length = " + iarr.length);
636     }
637 
638     /**
639      * tests getting a 'whatever' property
640      */
641     @Test
642     public void testGetGeneralProperty() throws Exception {
643         final String val = BeanUtils.getProperty(bean, "nested.intIndexed[2]");
644         final String comp = String.valueOf(bean.get("intIndexed", 2));
645 
646         assertEquals(val, comp, "nested.intIndexed[2] == " + comp);
647     }
648 
649     /**
650      * tests getting an indexed property
651      */
652     @Test
653     public void testGetIndexedProperty1() throws Exception {
654         String val = BeanUtils.getIndexedProperty(bean, "intIndexed[3]");
655         String comp = String.valueOf(bean.get("intIndexed", 3));
656         assertEquals(val, comp, "intIndexed[3] == " + comp);
657 
658         val = BeanUtils.getIndexedProperty(bean, "stringIndexed[3]");
659         comp = (String) bean.get("stringIndexed", 3);
660         assertEquals(val, comp, "stringIndexed[3] == " + comp);
661     }
662 
663     /**
664      * tests getting an indexed property
665      */
666     @Test
667     public void testGetIndexedProperty2() throws Exception {
668         String val = BeanUtils.getIndexedProperty(bean, "intIndexed", 3);
669         String comp = String.valueOf(bean.get("intIndexed", 3));
670 
671         assertEquals(val, comp, "intIndexed,3 == " + comp);
672 
673         val = BeanUtils.getIndexedProperty(bean, "stringIndexed", 3);
674         comp = (String) bean.get("stringIndexed", 3);
675 
676         assertEquals(val, comp, "stringIndexed,3 == " + comp);
677     }
678 
679     /**
680      * tests getting a nested property
681      */
682     @Test
683     public void testGetNestedProperty() throws Exception {
684         final String val = BeanUtils.getNestedProperty(bean, "nested.stringProperty");
685         final String comp = nested.getStringProperty();
686         assertEquals(val, comp, "nested.StringProperty == " + comp);
687     }
688 
689     /**
690      * tests getting a 'whatever' property
691      */
692     @Test
693     public void testGetSimpleProperty() throws Exception {
694         final String val = BeanUtils.getSimpleProperty(bean, "shortProperty");
695         final String comp = String.valueOf(bean.get("shortProperty"));
696 
697         assertEquals(val, comp, "shortProperty == " + comp);
698     }
699 
700     /**
701      * Test populate() method on individual array elements.
702      */
703     @Test
704     public void testPopulateArrayElements() throws Exception {
705         final HashMap<String, Object> map = new HashMap<>();
706         map.put("intIndexed[0]", "100");
707         map.put("intIndexed[2]", "120");
708         map.put("intIndexed[4]", "140");
709 
710         BeanUtils.populate(bean, map);
711         final Integer intIndexed0 = (Integer) bean.get("intIndexed", 0);
712         assertEquals(100, intIndexed0.intValue(), "intIndexed[0] is 100");
713         final Integer intIndexed1 = (Integer) bean.get("intIndexed", 1);
714         assertEquals(10, intIndexed1.intValue(), "intIndexed[1] is 10");
715         final Integer intIndexed2 = (Integer) bean.get("intIndexed", 2);
716         assertEquals(120, intIndexed2.intValue(), "intIndexed[2] is 120");
717         final Integer intIndexed3 = (Integer) bean.get("intIndexed", 3);
718         assertEquals(30, intIndexed3.intValue(), "intIndexed[3] is 30");
719         final Integer intIndexed4 = (Integer) bean.get("intIndexed", 4);
720         assertEquals(140, intIndexed4.intValue(), "intIndexed[4] is 140");
721 
722         map.clear();
723         map.put("stringIndexed[1]", "New String 1");
724         map.put("stringIndexed[3]", "New String 3");
725 
726         BeanUtils.populate(bean, map);
727 
728         assertEquals("String 0", (String) bean.get("stringIndexed", 0), "stringIndexed[0] is \"String 0\"");
729         assertEquals("New String 1", (String) bean.get("stringIndexed", 1), "stringIndexed[1] is \"New String 1\"");
730         assertEquals("String 2", (String) bean.get("stringIndexed", 2), "stringIndexed[2] is \"String 2\"");
731         assertEquals("New String 3", (String) bean.get("stringIndexed", 3), "stringIndexed[3] is \"New String 3\"");
732         assertEquals("String 4", (String) bean.get("stringIndexed", 4), "stringIndexed[4] is \"String 4\"");
733     }
734 
735     /**
736      * Test populate() method on array properties as a whole.
737      */
738     @Test
739     public void testPopulateArrayProperties() throws Exception {
740         final HashMap<String, Object> map = new HashMap<>();
741         // int[] intArray = new int[] { 123, 456, 789 };
742         final String[] intArrayIn = { "123", "456", "789" };
743         map.put("intArray", intArrayIn);
744         String[] stringArray = { "New String 0", "New String 1" };
745         map.put("stringArray", stringArray);
746 
747         BeanUtils.populate(bean, map);
748 
749         final int[] intArray = (int[]) bean.get("intArray");
750         assertNotNull(intArray, "intArray is present");
751         assertEquals(3, intArray.length, "intArray length");
752         assertEquals(123, intArray[0], "intArray[0]");
753         assertEquals(456, intArray[1], "intArray[1]");
754         assertEquals(789, intArray[2], "intArray[2]");
755         stringArray = (String[]) bean.get("stringArray");
756         assertNotNull(stringArray, "stringArray is present");
757         assertEquals(2, stringArray.length, "stringArray length");
758         assertEquals("New String 0", stringArray[0], "stringArray[0]");
759         assertEquals("New String 1", stringArray[1], "stringArray[1]");
760     }
761 
762     /**
763      * Test populate() on mapped properties.
764      */
765     @Test
766     public void testPopulateMapped() throws Exception {
767         final HashMap<String, Object> map = new HashMap<>();
768         map.put("mappedProperty(First Key)", "New First Value");
769         map.put("mappedProperty(Third Key)", "New Third Value");
770 
771         BeanUtils.populate(bean, map);
772 
773         assertEquals("New First Value", (String) bean.get("mappedProperty", "First Key"), "mappedProperty(First Key)");
774         assertEquals("Second Value", (String) bean.get("mappedProperty", "Second Key"), "mappedProperty(Second Key)");
775         assertEquals("New Third Value", (String) bean.get("mappedProperty", "Third Key"), "mappedProperty(Third Key)");
776         assertNull(bean.get("mappedProperty", "Fourth Key"), "mappedProperty(Fourth Key");
777     }
778 
779     /**
780      * Test populate() method on nested properties.
781      */
782     @Test
783     public void testPopulateNested() throws Exception {
784         final HashMap<String, Object> map = new HashMap<>();
785         map.put("nested.booleanProperty", "false");
786         // booleanSecond is left at true
787         map.put("nested.doubleProperty", "432.0");
788         // floatProperty is left at 123.0
789         map.put("nested.intProperty", "543");
790         // longProperty is left at 321
791         map.put("nested.shortProperty", "654");
792         // stringProperty is left at "This is a string"
793 
794         BeanUtils.populate(bean, map);
795 
796         final TestBean nested = (TestBean) bean.get("nested");
797         assertFalse(nested.getBooleanProperty(), "booleanProperty is false");
798         assertTrue(nested.isBooleanSecond(), "booleanSecond is true");
799         assertEquals(432.0, nested.getDoubleProperty(), 0.005, "doubleProperty is 432.0");
800         assertEquals((float) 123.0, nested.getFloatProperty(), (float) 0.005, "floatProperty is 123.0");
801         assertEquals(543, nested.getIntProperty(), "intProperty is 543");
802         assertEquals(321, nested.getLongProperty(), "longProperty is 321");
803         assertEquals((short) 654, nested.getShortProperty(), "shortProperty is 654");
804         assertEquals("This is a string", nested.getStringProperty(), "stringProperty is \"This is a string\"");
805     }
806 
807     /**
808      * Test populate() method on scalar properties.
809      */
810     @Test
811     public void testPopulateScalar() throws Exception {
812         bean.set("nullProperty", "non-null value");
813 
814         final HashMap<String, Object> map = new HashMap<>();
815         map.put("booleanProperty", "false");
816         // booleanSecond is left at true
817         map.put("doubleProperty", "432.0");
818         // floatProperty is left at 123.0
819         map.put("intProperty", "543");
820         // longProperty is left at 321
821         map.put("nullProperty", null);
822         map.put("shortProperty", "654");
823         // stringProperty is left at "This is a string"
824 
825         BeanUtils.populate(bean, map);
826 
827         final Boolean booleanProperty = (Boolean) bean.get("booleanProperty");
828         assertFalse(booleanProperty.booleanValue(), "booleanProperty is false");
829         final Boolean booleanSecond = (Boolean) bean.get("booleanSecond");
830         assertTrue(booleanSecond.booleanValue(), "booleanSecond is true");
831         final Double doubleProperty = (Double) bean.get("doubleProperty");
832         assertEquals(432.0, doubleProperty.doubleValue(), 0.005, "doubleProperty is 432.0");
833         final Float floatProperty = (Float) bean.get("floatProperty");
834         assertEquals((float) 123.0, floatProperty.floatValue(), (float) 0.005, "floatProperty is 123.0");
835         final Integer intProperty = (Integer) bean.get("intProperty");
836         assertEquals(543, intProperty.intValue(), "intProperty is 543");
837         final Long longProperty = (Long) bean.get("longProperty");
838         assertEquals(321, longProperty.longValue(), "longProperty is 321");
839         assertNull(bean.get("nullProperty"), "nullProperty is null");
840         final Short shortProperty = (Short) bean.get("shortProperty");
841         assertEquals((short) 654, shortProperty.shortValue(), "shortProperty is 654");
842         assertEquals("This is a string", (String) bean.get("stringProperty"), "stringProperty is \"This is a string\"");
843     }
844 
845     /**
846      * Test setting a null property value.
847      */
848     @Test
849     public void testSetPropertyNull() throws Exception {
850 
851         bean.set("nullProperty", "non-null value");
852         BeanUtils.setProperty(bean, "nullProperty", null);
853         assertNull(bean.get("nullProperty"), "nullProperty is null");
854 
855     }
856 
857     /**
858      * Test calling setProperty() with null property values.
859      */
860     @Test
861     public void testSetPropertyNullValues() throws Exception {
862 
863         Object oldValue;
864         Object newValue;
865 
866         // Scalar value into array
867         oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
868         BeanUtils.setProperty(bean, "stringArray", null);
869         newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
870         assertNotNull(newValue, "stringArray is not null");
871         assertInstanceOf(String[].class, newValue, "stringArray of correct type");
872         assertEquals(1, ((String[]) newValue).length, "stringArray length");
873         PropertyUtils.setProperty(bean, "stringArray", oldValue);
874 
875         // Indexed value into array
876         oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
877         BeanUtils.setProperty(bean, "stringArray[2]", null);
878         newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
879         assertNotNull(newValue, "stringArray is not null");
880         assertInstanceOf(String[].class, newValue, "stringArray of correct type");
881         assertEquals(5, ((String[]) newValue).length, "stringArray length");
882         assertNull(((String[]) newValue)[2], "stringArray[2] is null");
883         PropertyUtils.setProperty(bean, "stringArray", oldValue);
884 
885         // Value into scalar
886         BeanUtils.setProperty(bean, "stringProperty", null);
887         assertNull(BeanUtils.getProperty(bean, "stringProperty"), "stringProperty is now null");
888 
889     }
890 
891     /**
892      * Test converting to and from primitive wrapper types.
893      */
894     @Test
895     public void testSetPropertyOnPrimitiveWrappers() throws Exception {
896 
897         BeanUtils.setProperty(bean, "intProperty", Integer.valueOf(1));
898         assertEquals(1, ((Integer) bean.get("intProperty")).intValue());
899         BeanUtils.setProperty(bean, "stringProperty", Integer.valueOf(1));
900         assertEquals(1, Integer.parseInt((String) bean.get("stringProperty")));
901 
902     }
903 
904 }