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.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.util.ArrayList;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  import org.junit.jupiter.api.AfterEach;
34  import org.junit.jupiter.api.BeforeEach;
35  import org.junit.jupiter.api.Test;
36  
37  /**
38   * Test accessing DynaBeans transparently via PropertyUtils.
39   */
40  public class DynaPropertyUtilsTest {
41  
42      /**
43       * The basic test bean for each test.
44       */
45      protected DynaBean bean;
46  
47      /**
48       * The set of properties that should be described.
49       */
50      protected String[] describes = { "booleanProperty", "booleanSecond", "doubleProperty", "floatProperty", "intArray", "intIndexed", "intProperty",
51              "listIndexed", "longProperty", "mappedObjects", "mappedProperty", "mappedIntProperty", "nested", "nullProperty",
52              // "readOnlyProperty",
53              "shortProperty", "stringArray", "stringIndexed", "stringProperty" };
54  
55      /**
56       * The nested bean pointed at by the "nested" property.
57       */
58      protected TestBean nested;
59  
60      /**
61       * Create and return a {@code DynaClass} instance for our test {@code DynaBean}.
62       */
63      protected DynaClass createDynaClass() {
64          final int[] intArray = {};
65          final String[] stringArray = {};
66          return new BasicDynaClass("TestDynaClass", null, new DynaProperty[] { new DynaProperty("booleanProperty", Boolean.TYPE),
67                  new DynaProperty("booleanSecond", Boolean.TYPE), new DynaProperty("doubleProperty", Double.TYPE),
68                  new DynaProperty("dupProperty", stringArray.getClass()), new DynaProperty("floatProperty", Float.TYPE),
69                  new DynaProperty("intArray", intArray.getClass()), new DynaProperty("intIndexed", intArray.getClass()),
70                  new DynaProperty("intProperty", Integer.TYPE), new DynaProperty("listIndexed", List.class), new DynaProperty("longProperty", Long.TYPE),
71                  new DynaProperty("mapProperty", Map.class), new DynaProperty("mappedObjects", Map.class), new DynaProperty("mappedProperty", Map.class),
72                  new DynaProperty("mappedIntProperty", Map.class), new DynaProperty("nested", TestBean.class), new DynaProperty("nullProperty", String.class),
73                  new DynaProperty("shortProperty", Short.TYPE), new DynaProperty("stringArray", stringArray.getClass()),
74                  new DynaProperty("stringIndexed", stringArray.getClass()), new DynaProperty("stringProperty", String.class), });
75      }
76  
77      /**
78       * Sets up instance variables required by this test case.
79       */
80      @BeforeEach
81      public void setUp() throws Exception {
82          // Instantiate a new DynaBean instance
83          final DynaClass dynaClass = createDynaClass();
84          bean = dynaClass.newInstance();
85          // Initialize the DynaBean's property values (like TestBean)
86          bean.set("booleanProperty", Boolean.valueOf(true));
87          bean.set("booleanSecond", Boolean.valueOf(true));
88          bean.set("doubleProperty", Double.valueOf(321.0));
89          bean.set("floatProperty", Float.valueOf((float) 123.0));
90          final int[] intArray = { 0, 10, 20, 30, 40 };
91          bean.set("intArray", intArray);
92          final int[] intIndexed = { 0, 10, 20, 30, 40 };
93          bean.set("intIndexed", intIndexed);
94          bean.set("intProperty", Integer.valueOf(123));
95          final List<String> listIndexed = new ArrayList<>();
96          listIndexed.add("String 0");
97          listIndexed.add("String 1");
98          listIndexed.add("String 2");
99          listIndexed.add("String 3");
100         listIndexed.add("String 4");
101         bean.set("listIndexed", listIndexed);
102         bean.set("longProperty", Long.valueOf(321));
103         final HashMap<String, Object> mapProperty = new HashMap<>();
104         mapProperty.put("First Key", "First Value");
105         mapProperty.put("Second Key", "Second Value");
106         bean.set("mapProperty", mapProperty);
107         final HashMap<String, Object> mappedObjects = new HashMap<>();
108         mappedObjects.put("First Key", "First Value");
109         mappedObjects.put("Second Key", "Second Value");
110         bean.set("mappedObjects", mappedObjects);
111         final HashMap<String, Object> mappedProperty = new HashMap<>();
112         mappedProperty.put("First Key", "First Value");
113         mappedProperty.put("Second Key", "Second Value");
114         bean.set("mappedProperty", mappedProperty);
115         final HashMap<String, Integer> mappedIntProperty = new HashMap<>();
116         mappedIntProperty.put("One", Integer.valueOf(1));
117         mappedIntProperty.put("Two", Integer.valueOf(2));
118         bean.set("mappedIntProperty", mappedIntProperty);
119         nested = new TestBean();
120         bean.set("nested", nested);
121         // Property "nullProperty" is not initialized, so it should return null
122         bean.set("shortProperty", Short.valueOf((short) 987));
123         final String[] stringArray = { "String 0", "String 1", "String 2", "String 3", "String 4" };
124         bean.set("stringArray", stringArray);
125         final String[] stringIndexed = { "String 0", "String 1", "String 2", "String 3", "String 4" };
126         bean.set("stringIndexed", stringIndexed);
127         bean.set("stringProperty", "This is a string");
128 
129     }
130 
131     /**
132      * Tear down instance variables required by this test case.
133      */
134     @AfterEach
135     public void tearDown() {
136         bean = null;
137         nested = null;
138     }
139 
140     /**
141      * Test copyProperties() when the origin is a {@code Map}.
142      */
143     @Test
144     public void testCopyPropertiesMap() throws Exception {
145         final Map<String, Object> map = new HashMap<>();
146         map.put("booleanProperty", Boolean.FALSE);
147         map.put("doubleProperty", Double.valueOf(333.0));
148         map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
149         map.put("floatProperty", Float.valueOf((float) 222.0));
150         map.put("intArray", new int[] { 0, 100, 200 });
151         map.put("intProperty", Integer.valueOf(111));
152         map.put("longProperty", Long.valueOf(444));
153         map.put("shortProperty", Short.valueOf((short) 555));
154         map.put("stringProperty", "New String Property");
155         PropertyUtils.copyProperties(bean, map);
156 
157         // Scalar properties
158         assertEquals(false, ((Boolean) bean.get("booleanProperty")).booleanValue(), "booleanProperty");
159         assertEquals(333.0, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005, "doubleProperty");
160         assertEquals((float) 222.0, ((Float) bean.get("floatProperty")).floatValue(), (float) 0.005, "floatProperty");
161         assertEquals(111, ((Integer) bean.get("intProperty")).intValue(), "intProperty");
162         assertEquals(444, ((Long) bean.get("longProperty")).longValue(), "longProperty");
163         assertEquals((short) 555, ((Short) bean.get("shortProperty")).shortValue(), "shortProperty");
164         assertEquals("New String Property", (String) bean.get("stringProperty"), "stringProperty");
165 
166         // Indexed Properties
167         final String[] dupProperty = (String[]) bean.get("dupProperty");
168         assertNotNull(dupProperty, "dupProperty present");
169         assertEquals(3, dupProperty.length, "dupProperty length");
170         assertEquals("New 0", dupProperty[0], "dupProperty[0]");
171         assertEquals("New 1", dupProperty[1], "dupProperty[1]");
172         assertEquals("New 2", dupProperty[2], "dupProperty[2]");
173         final int[] intArray = (int[]) bean.get("intArray");
174         assertNotNull(intArray, "intArray present");
175         assertEquals(3, intArray.length, "intArray length");
176         assertEquals(0, intArray[0], "intArray[0]");
177         assertEquals(100, intArray[1], "intArray[1]");
178         assertEquals(200, intArray[2], "intArray[2]");
179 
180     }
181 
182     /**
183      * Test the describe() method.
184      */
185     @Test
186     public void testDescribe() throws Exception {
187 
188         final Map<String, Object> map = PropertyUtils.describe(bean);
189 
190         // Verify existence of all the properties that should be present
191         for (final String describe : describes) {
192             assertTrue(map.containsKey(describe), "Property '" + describe + "' is present");
193         }
194         assertFalse(map.containsKey("writeOnlyProperty"), "Property 'writeOnlyProperty' is not present");
195 
196         // Verify the values of scalar properties
197         assertEquals(Boolean.TRUE, map.get("booleanProperty"), "Value of 'booleanProperty'");
198         assertEquals(Double.valueOf(321.0), map.get("doubleProperty"), "Value of 'doubleProperty'");
199         assertEquals(Float.valueOf((float) 123.0), map.get("floatProperty"), "Value of 'floatProperty'");
200         assertEquals(Integer.valueOf(123), map.get("intProperty"), "Value of 'intProperty'");
201         assertEquals(Long.valueOf(321), map.get("longProperty"), "Value of 'longProperty'");
202         assertEquals(Short.valueOf((short) 987), map.get("shortProperty"), "Value of 'shortProperty'");
203         assertEquals("This is a string", (String) map.get("stringProperty"), "Value of 'stringProperty'");
204 
205     }
206 
207     /**
208      * Corner cases on getIndexedProperty invalid arguments.
209      */
210     @Test
211     public void testGetIndexedArguments() {
212         // Use explicit index argument
213         assertThrows(NullPointerException.class, () -> PropertyUtils.getIndexedProperty(null, "intArray", 0));
214         assertThrows(NullPointerException.class, () -> PropertyUtils.getIndexedProperty(bean, null, 0));
215         // Use index expression
216         assertThrows(NullPointerException.class, () -> PropertyUtils.getIndexedProperty(null, "intArray[0]"));
217         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.getIndexedProperty(bean, "[0]"));
218         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.getIndexedProperty(bean, "intArray"));
219         // Use explicit index argument
220         assertThrows(NullPointerException.class, () -> PropertyUtils.getIndexedProperty(null, "intIndexed", 0));
221         assertThrows(NullPointerException.class, () -> PropertyUtils.getIndexedProperty(bean, null, 0));
222         // Use index expression
223         assertThrows(NullPointerException.class, () -> PropertyUtils.getIndexedProperty(null, "intIndexed[0]"));
224         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.getIndexedProperty(bean, "[0]"));
225         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.getIndexedProperty(bean, "intIndexed"));
226     }
227 
228     /**
229      * Positive and negative tests on getIndexedProperty valid arguments.
230      */
231     @Test
232     public void testGetIndexedValues() throws Exception {
233         Object value = null;
234         // Use explicit key argument
235         for (int i = 0; i < 5; i++) {
236             value = PropertyUtils.getIndexedProperty(bean, "intArray", i);
237             assertNotNull(value, "intArray returned value " + i);
238             assertInstanceOf(Integer.class, value, "intArray returned Integer " + i);
239             assertEquals(i * 10, ((Integer) value).intValue(), "intArray returned correct " + i);
240 
241             value = PropertyUtils.getIndexedProperty(bean, "intIndexed", i);
242             assertNotNull(value, "intIndexed returned value " + i);
243             assertInstanceOf(Integer.class, value, "intIndexed returned Integer " + i);
244             assertEquals(i * 10, ((Integer) value).intValue(), "intIndexed returned correct " + i);
245 
246             value = PropertyUtils.getIndexedProperty(bean, "listIndexed", i);
247             assertNotNull(value, "listIndexed returned value " + i);
248             assertInstanceOf(String.class, value, "list returned String " + i);
249             assertEquals("String " + i, (String) value, "listIndexed returned correct " + i);
250 
251             value = PropertyUtils.getIndexedProperty(bean, "stringArray", i);
252             assertNotNull(value, "stringArray returned value " + i);
253             assertInstanceOf(String.class, value, "stringArray returned String " + i);
254             assertEquals("String " + i, (String) value, "stringArray returned correct " + i);
255 
256             value = PropertyUtils.getIndexedProperty(bean, "stringIndexed", i);
257             assertNotNull(value, "stringIndexed returned value " + i);
258             assertInstanceOf(String.class, value, "stringIndexed returned String " + i);
259             assertEquals("String " + i, (String) value, "stringIndexed returned correct " + i);
260         }
261         // Use key expression
262         for (int i = 0; i < 5; i++) {
263             value = PropertyUtils.getIndexedProperty(bean, "intArray[" + i + "]");
264             assertNotNull(value, "intArray returned value " + i);
265             assertInstanceOf(Integer.class, value, "intArray returned Integer " + i);
266             assertEquals(i * 10, ((Integer) value).intValue(), "intArray returned correct " + i);
267 
268             value = PropertyUtils.getIndexedProperty(bean, "intIndexed[" + i + "]");
269             assertNotNull(value, "intIndexed returned value " + i);
270             assertInstanceOf(Integer.class, value, "intIndexed returned Integer " + i);
271             assertEquals(i * 10, ((Integer) value).intValue(), "intIndexed returned correct " + i);
272 
273             value = PropertyUtils.getIndexedProperty(bean, "listIndexed[" + i + "]");
274             assertNotNull(value, "listIndexed returned value " + i);
275             assertInstanceOf(String.class, value, "listIndexed returned String " + i);
276             assertEquals("String " + i, (String) value, "listIndexed returned correct " + i);
277 
278             value = PropertyUtils.getIndexedProperty(bean, "stringArray[" + i + "]");
279             assertNotNull(value, "stringArray returned value " + i);
280             assertInstanceOf(String.class, value, "stringArray returned String " + i);
281             assertEquals("String " + i, (String) value, "stringArray returned correct " + i);
282 
283             value = PropertyUtils.getIndexedProperty(bean, "stringIndexed[" + i + "]");
284             assertNotNull(value, "stringIndexed returned value " + i);
285             assertInstanceOf(String.class, value, "stringIndexed returned String " + i);
286             assertEquals("String " + i, (String) value, "stringIndexed returned correct " + i);
287         }
288 
289         // Index out of bounds tests
290         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "intArray", -1));
291         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "intArray", 5));
292         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "intIndexed", -1));
293         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "intIndexed", 5));
294         assertThrows(IndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "listIndexed", -1));
295         assertThrows(IndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "listIndexed", 5));
296         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "stringArray", -1));
297         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "stringArray", 5));
298         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "stringIndexed", -1));
299         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.getIndexedProperty(bean, "stringIndexed", 5));
300     }
301 
302     /**
303      * Corner cases on getMappedProperty invalid arguments.
304      */
305     @Test
306     public void testGetMappedArguments() {
307         // Use explicit key argument
308         assertThrows(NullPointerException.class, () -> PropertyUtils.getMappedProperty(null, "mappedProperty", "First Key"));
309         assertThrows(NullPointerException.class, () -> PropertyUtils.getMappedProperty(bean, null, "First Key"));
310         assertThrows(NullPointerException.class, () -> PropertyUtils.getMappedProperty(bean, "mappedProperty", null));
311         // Use key expression
312         assertThrows(NullPointerException.class, () -> PropertyUtils.getMappedProperty(null, "mappedProperty(First Key)"));
313         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.getMappedProperty(bean, "(Second Key)"));
314         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.getMappedProperty(bean, "mappedProperty"));
315 
316     }
317 
318     /**
319      * Test getting mapped values with periods in the key.
320      */
321     @Test
322     public void testGetMappedPeriods() throws Exception {
323         bean.set("mappedProperty", "key.with.a.dot", "Special Value");
324         assertEquals("Special Value", (String) bean.get("mappedProperty", "key.with.a.dot"), "Can retrieve directly");
325         assertEquals("Special Value", PropertyUtils.getMappedProperty(bean, "mappedProperty", "key.with.a.dot"), "Can retrieve via getMappedProperty");
326         assertEquals("Special Value", PropertyUtils.getNestedProperty(bean, "mappedProperty(key.with.a.dot)"), "Can retrieve via getNestedProperty");
327 
328         bean.set("mappedObjects", "nested.property", new TestBean());
329         assertNotNull(bean.get("mappedObjects", "nested.property"), "Can retrieve directly");
330         assertEquals("This is a string", PropertyUtils.getNestedProperty(bean, "mappedObjects(nested.property).stringProperty"), "Can retrieve nested");
331     }
332 
333     /**
334      * Test getting mapped values with slashes in the key. This is different from periods because slashes are not syntactically significant.
335      */
336     @Test
337     public void testGetMappedSlashes() throws Exception {
338 
339         bean.set("mappedProperty", "key/with/a/slash", "Special Value");
340         assertEquals("Special Value", bean.get("mappedProperty", "key/with/a/slash"), "Can retrieve directly");
341         assertEquals("Special Value", PropertyUtils.getMappedProperty(bean, "mappedProperty", "key/with/a/slash"), "Can retrieve via getMappedProperty");
342         assertEquals("Special Value", PropertyUtils.getNestedProperty(bean, "mappedProperty(key/with/a/slash)"), "Can retrieve via getNestedProperty");
343         bean.set("mappedObjects", "nested/property", new TestBean());
344         assertNotNull(bean.get("mappedObjects", "nested/property"), "Can retrieve directly");
345         assertEquals("This is a string", PropertyUtils.getNestedProperty(bean, "mappedObjects(nested/property).stringProperty"), "Can retrieve nested");
346     }
347 
348     /**
349      * Positive and negative tests on getMappedProperty valid arguments.
350      */
351     @Test
352     public void testGetMappedValues() throws Exception {
353         Object value = null;
354         // Use explicit key argument
355         value = PropertyUtils.getMappedProperty(bean, "mappedProperty", "First Key");
356         assertEquals("First Value", value, "Can find first value");
357 
358         value = PropertyUtils.getMappedProperty(bean, "mappedProperty", "Second Key");
359         assertEquals("Second Value", value, "Can find second value");
360 
361         value = PropertyUtils.getMappedProperty(bean, "mappedProperty", "Third Key");
362         assertNull(value, "Can not find third value");
363 
364         // Use key expression with parentheses
365         value = PropertyUtils.getMappedProperty(bean, "mappedProperty(First Key)");
366         assertEquals("First Value", value, "Can find first value");
367 
368         value = PropertyUtils.getMappedProperty(bean, "mappedProperty(Second Key)");
369         assertEquals("Second Value", value, "Can find second value");
370 
371         value = PropertyUtils.getMappedProperty(bean, "mappedProperty(Third Key)");
372         assertNull(value, "Can not find third value");
373 
374         // Use key expression with dotted syntax
375 
376         value = PropertyUtils.getNestedProperty(bean, "mapProperty.First Key");
377         assertEquals("First Value", value, "Can find first value");
378 
379         value = PropertyUtils.getNestedProperty(bean, "mapProperty.Second Key");
380         assertEquals("Second Value", value, "Can find second value");
381 
382         value = PropertyUtils.getNestedProperty(bean, "mapProperty.Third Key");
383         assertNull(value, "Can not find third value");
384     }
385 
386     /**
387      * Corner cases on getNestedProperty invalid arguments.
388      */
389     @Test
390     public void testGetNestedArguments() {
391         assertThrows(NullPointerException.class, () -> PropertyUtils.getNestedProperty(null, "stringProperty"));
392         assertThrows(NullPointerException.class, () -> PropertyUtils.getNestedProperty(bean, null));
393     }
394 
395     /**
396      * Test getNestedProperty on a boolean property.
397      */
398     @Test
399     public void testGetNestedBoolean() throws Exception {
400         final Object value = PropertyUtils.getNestedProperty(bean, "nested.booleanProperty");
401         assertNotNull(value, "Got a value");
402         assertInstanceOf(Boolean.class, value, "Got correct type");
403         final TestBean nested = (TestBean) bean.get("nested");
404         assertEquals(((Boolean) value).booleanValue(), nested.getBooleanProperty(), "Got correct value");
405     }
406 
407     /**
408      * Test getNestedProperty on a double property.
409      */
410     @Test
411     public void testGetNestedDouble() throws Exception {
412         final Object value = PropertyUtils.getNestedProperty(bean, "nested.doubleProperty");
413         assertNotNull(value, "Got a value");
414         assertInstanceOf(Double.class, value, "Got correct type");
415         final TestBean nested = (TestBean) bean.get("nested");
416         assertEquals(((Double) value).doubleValue(), nested.getDoubleProperty(), 0.005, "Got correct value");
417     }
418 
419     /**
420      * Test getNestedProperty on a float property.
421      */
422     @Test
423     public void testGetNestedFloat() throws Exception {
424         final Object value = PropertyUtils.getNestedProperty(bean, "nested.floatProperty");
425         assertNotNull(value, "Got a value");
426         assertInstanceOf(Float.class, value, "Got correct type");
427         final TestBean nested = (TestBean) bean.get("nested");
428         assertEquals(((Float) value).floatValue(), nested.getFloatProperty(), (float) 0.005, "Got correct value");
429     }
430 
431     /**
432      * Test getNestedProperty on an int property.
433      */
434     @Test
435     public void testGetNestedInt() throws Exception {
436         final Object value = PropertyUtils.getNestedProperty(bean, "nested.intProperty");
437         assertNotNull(value, "Got a value");
438         assertInstanceOf(Integer.class, value, "Got correct type");
439         final TestBean nested = (TestBean) bean.get("nested");
440         assertEquals(((Integer) value).intValue(), nested.getIntProperty(), "Got correct value");
441     }
442 
443     /**
444      * Test getNestedProperty on a long property.
445      */
446     @Test
447     public void testGetNestedLong() throws Exception {
448         final Object value = PropertyUtils.getNestedProperty(bean, "nested.longProperty");
449         assertNotNull(value, "Got a value");
450         assertInstanceOf(Long.class, value, "Got correct type");
451         final TestBean nested = (TestBean) bean.get("nested");
452         assertEquals(((Long) value).longValue(), nested.getLongProperty(), "Got correct value");
453     }
454 
455     /**
456      * Test getNestedProperty on a read-only String property.
457      */
458     @Test
459     public void testGetNestedReadOnly() throws Exception {
460         final Object value = PropertyUtils.getNestedProperty(bean, "nested.readOnlyProperty");
461         assertNotNull(value, "Got a value");
462         assertInstanceOf(String.class, value, "Got correct type");
463         final TestBean nested = (TestBean) bean.get("nested");
464         assertEquals((String) value, nested.getReadOnlyProperty(), "Got correct value");
465     }
466 
467     /**
468      * Test getNestedProperty on a short property.
469      */
470     @Test
471     public void testGetNestedShort() throws Exception {
472         final Object value = PropertyUtils.getNestedProperty(bean, "nested.shortProperty");
473         assertNotNull(value, "Got a value");
474         assertInstanceOf(Short.class, value, "Got correct type");
475         final TestBean nested = (TestBean) bean.get("nested");
476         assertEquals(((Short) value).shortValue(), nested.getShortProperty(), "Got correct value");
477     }
478 
479     /**
480      * Test getNestedProperty on a String property.
481      */
482     @Test
483     public void testGetNestedString() throws Exception {
484         final Object value = PropertyUtils.getNestedProperty(bean, "nested.stringProperty");
485         assertNotNull(value, "Got a value");
486         assertInstanceOf(String.class, value, "Got correct type");
487         final TestBean nested = (TestBean) bean.get("nested");
488         assertEquals((String) value, nested.getStringProperty(), "Got correct value");
489     }
490 
491     /**
492      * Negative test getNestedProperty on an unknown property.
493      */
494     @Test
495     public void testGetNestedUnknown() throws Exception {
496         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.getNestedProperty(bean, "nested.unknown"));
497     }
498 
499     /**
500      * Corner cases on getSimpleProperty invalid arguments.
501      */
502     @Test
503     public void testGetSimpleArguments() {
504         assertThrows(NullPointerException.class, () -> PropertyUtils.getSimpleProperty(null, "stringProperty"));
505         assertThrows(NullPointerException.class, () -> PropertyUtils.getSimpleProperty(bean, null));
506     }
507 
508     /**
509      * Test getSimpleProperty on a boolean property.
510      */
511     @Test
512     public void testGetSimpleBoolean() throws Exception {
513         final Object value = PropertyUtils.getSimpleProperty(bean, "booleanProperty");
514         assertNotNull(value, "Got a value");
515         assertInstanceOf(Boolean.class, value, "Got correct type");
516         assertTrue(((Boolean) value).booleanValue(), "Got correct value");
517     }
518 
519     /**
520      * Test getSimpleProperty on a double property.
521      */
522     @Test
523     public void testGetSimpleDouble() throws Exception {
524         final Object value = PropertyUtils.getSimpleProperty(bean, "doubleProperty");
525         assertNotNull(value, "Got a value");
526         assertInstanceOf(Double.class, value, "Got correct type");
527         assertEquals(((Double) value).doubleValue(), 321.0, 0.005, "Got correct value");
528     }
529 
530     /**
531      * Test getSimpleProperty on a float property.
532      */
533     @Test
534     public void testGetSimpleFloat() throws Exception {
535         final Object value = PropertyUtils.getSimpleProperty(bean, "floatProperty");
536         assertNotNull(value, "Got a value");
537         assertInstanceOf(Float.class, value, "Got correct type");
538         assertEquals(((Float) value).floatValue(), (float) 123.0, (float) 0.005, "Got correct value");
539     }
540 
541     /**
542      * Negative test getSimpleProperty on an indexed property.
543      */
544     @Test
545     public void testGetSimpleIndexed() throws Exception {
546         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.getSimpleProperty(bean, "intIndexed[0]"));
547     }
548 
549     /**
550      * Test getSimpleProperty on an int property.
551      */
552     @Test
553     public void testGetSimpleInt() throws Exception {
554         final Object value = PropertyUtils.getSimpleProperty(bean, "intProperty");
555         assertNotNull(value, "Got a value");
556         assertInstanceOf(Integer.class, value, "Got correct type");
557         assertEquals(((Integer) value).intValue(), 123, "Got correct value");
558     }
559 
560     /**
561      * Test getSimpleProperty on a long property.
562      */
563     @Test
564     public void testGetSimpleLong() throws Exception {
565         final Object value = PropertyUtils.getSimpleProperty(bean, "longProperty");
566         assertNotNull(value, "Got a value");
567         assertInstanceOf(Long.class, value, "Got correct type");
568         assertEquals(((Long) value).longValue(), 321, "Got correct value");
569     }
570 
571     /**
572      * Negative test getSimpleProperty on a nested property.
573      */
574     @Test
575     public void testGetSimpleNested() throws Exception {
576         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.getSimpleProperty(bean, "nested.stringProperty"));
577     }
578 
579     /**
580      * Test getSimpleProperty on a short property.
581      */
582     @Test
583     public void testGetSimpleShort() throws Exception {
584         final Object value = PropertyUtils.getSimpleProperty(bean, "shortProperty");
585         assertNotNull(value, "Got a value");
586         assertInstanceOf(Short.class, value, "Got correct type");
587         assertEquals(((Short) value).shortValue(), (short) 987, "Got correct value");
588     }
589 
590     /**
591      * Test getSimpleProperty on a String property.
592      */
593     @Test
594     public void testGetSimpleString() throws Exception {
595         final Object value = PropertyUtils.getSimpleProperty(bean, "stringProperty");
596         assertNotNull(value, "Got a value");
597         assertInstanceOf(String.class, value, "Got correct type");
598         assertEquals((String) value, "This is a string", "Got correct value");
599     }
600 
601     /**
602      * Negative test getSimpleProperty on an unknown property.
603      */
604     @Test
605     public void testGetSimpleUnknown() throws Exception {
606         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.getSimpleProperty(bean, "unknown"));
607     }
608 
609     /**
610      * Corner cases on setIndexedProperty invalid arguments.
611      */
612     @Test
613     public void testSetIndexedArguments() {
614         // Use explicit index argument
615         assertThrows(NullPointerException.class, () -> PropertyUtils.setIndexedProperty(null, "intArray", 0, Integer.valueOf(1)));
616         assertThrows(NullPointerException.class, () -> PropertyUtils.setIndexedProperty(bean, null, 0, Integer.valueOf(1)));
617         // Use index expression
618         assertThrows(NullPointerException.class, () -> PropertyUtils.setIndexedProperty(null, "intArray[0]", Integer.valueOf(1)));
619         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.setIndexedProperty(bean, "[0]", Integer.valueOf(1)));
620         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.setIndexedProperty(bean, "intArray", Integer.valueOf(1)));
621         // Use explicit index argument
622         assertThrows(NullPointerException.class, () -> PropertyUtils.setIndexedProperty(null, "intIndexed", 0, Integer.valueOf(1)));
623         assertThrows(NullPointerException.class, () -> PropertyUtils.setIndexedProperty(bean, null, 0, Integer.valueOf(1)));
624         // Use index expression
625         assertThrows(NullPointerException.class, () -> PropertyUtils.setIndexedProperty(null, "intIndexed[0]", Integer.valueOf(1)));
626         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.setIndexedProperty(bean, "[0]", Integer.valueOf(1)));
627         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.setIndexedProperty(bean, "intIndexed", Integer.valueOf(1)));
628     }
629 
630     /**
631      * Positive and negative tests on setIndexedProperty valid arguments.
632      */
633     @Test
634     public void testSetIndexedValues() throws Exception {
635         Object value = null;
636         // Use explicit index argument
637         PropertyUtils.setIndexedProperty(bean, "intArray", 0, Integer.valueOf(1));
638         value = PropertyUtils.getIndexedProperty(bean, "intArray", 0);
639         assertNotNull(value, "Returned new value 0");
640         assertInstanceOf(Integer.class, value, "Returned Integer new value 0");
641         assertEquals(1, ((Integer) value).intValue(), "Returned correct new value 0");
642 
643         PropertyUtils.setIndexedProperty(bean, "intIndexed", 1, Integer.valueOf(11));
644         value = PropertyUtils.getIndexedProperty(bean, "intIndexed", 1);
645         assertNotNull(value, "Returned new value 1");
646         assertInstanceOf(Integer.class, value, "Returned Integer new value 1");
647         assertEquals(11, ((Integer) value).intValue(), "Returned correct new value 1");
648 
649         PropertyUtils.setIndexedProperty(bean, "listIndexed", 2, "New Value 2");
650         value = PropertyUtils.getIndexedProperty(bean, "listIndexed", 2);
651         assertNotNull(value, "Returned new value 2");
652         assertInstanceOf(String.class, value, "Returned String new value 2");
653         assertEquals("New Value 2", (String) value, "Returned correct new value 2");
654 
655         PropertyUtils.setIndexedProperty(bean, "stringArray", 2, "New Value 2");
656         value = PropertyUtils.getIndexedProperty(bean, "stringArray", 2);
657         assertNotNull(value, "Returned new value 2");
658         assertInstanceOf(String.class, value, "Returned String new value 2");
659         assertEquals("New Value 2", (String) value, "Returned correct new value 2");
660 
661         PropertyUtils.setIndexedProperty(bean, "stringArray", 3, "New Value 3");
662         value = PropertyUtils.getIndexedProperty(bean, "stringArray", 3);
663         assertNotNull(value, "Returned new value 3");
664         assertInstanceOf(String.class, value, "Returned String new value 3");
665         assertEquals("New Value 3", (String) value, "Returned correct new value 3");
666 
667         // Use index expression
668         PropertyUtils.setIndexedProperty(bean, "intArray[4]", Integer.valueOf(1));
669         value = PropertyUtils.getIndexedProperty(bean, "intArray[4]");
670         assertNotNull(value, "Returned new value 4");
671         assertInstanceOf(Integer.class, value, "Returned Integer new value 4");
672         assertEquals(1, ((Integer) value).intValue(), "Returned correct new value 4");
673 
674         PropertyUtils.setIndexedProperty(bean, "intIndexed[3]", Integer.valueOf(11));
675         value = PropertyUtils.getIndexedProperty(bean, "intIndexed[3]");
676         assertNotNull(value, "Returned new value 5");
677         assertInstanceOf(Integer.class, value, "Returned Integer new value 5");
678         assertEquals(11, ((Integer) value).intValue(), "Returned correct new value 5");
679 
680         PropertyUtils.setIndexedProperty(bean, "listIndexed[1]", "New Value 2");
681         value = PropertyUtils.getIndexedProperty(bean, "listIndexed[1]");
682         assertNotNull(value, "Returned new value 6");
683         assertInstanceOf(String.class, value, "Returned String new value 6");
684         assertEquals("New Value 2", (String) value, "Returned correct new value 6");
685 
686         PropertyUtils.setIndexedProperty(bean, "stringArray[1]", "New Value 2");
687         value = PropertyUtils.getIndexedProperty(bean, "stringArray[2]");
688         assertNotNull(value, "Returned new value 6");
689         assertInstanceOf(String.class, value, "Returned String new value 6");
690         assertEquals("New Value 2", (String) value, "Returned correct new value 6");
691 
692         PropertyUtils.setIndexedProperty(bean, "stringArray[0]", "New Value 3");
693         value = PropertyUtils.getIndexedProperty(bean, "stringArray[0]");
694         assertNotNull(value, "Returned new value 7");
695         assertInstanceOf(String.class, value, "Returned String new value 7");
696         assertEquals("New Value 3", (String) value, "Returned correct new value 7");
697 
698         // Index out of bounds tests
699         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "intArray", -1, Integer.valueOf(0)));
700         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "intArray", 5, Integer.valueOf(0)));
701         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "intIndexed", -1, Integer.valueOf(0)));
702         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "intIndexed", 5, Integer.valueOf(0)));
703         assertThrows(IndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "listIndexed", 5, "New String"));
704         assertThrows(IndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "listIndexed", -1, "New String"));
705         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "stringArray", -1, "New String"));
706         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "stringArray", 5, "New String"));
707         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "stringIndexed", -1, "New String"));
708         assertThrows(ArrayIndexOutOfBoundsException.class, () -> PropertyUtils.setIndexedProperty(bean, "stringIndexed", 5, "New String"));
709     }
710 
711     /**
712      * Corner cases on getMappedProperty invalid arguments.
713      */
714     @Test
715     public void testSetMappedArguments() {
716         // Use explicit key argument
717         assertThrows(NullPointerException.class, () -> PropertyUtils.setMappedProperty(null, "mappedProperty", "First Key", "First Value"));
718         assertThrows(NullPointerException.class, () -> PropertyUtils.setMappedProperty(bean, null, "First Key", "First Value"));
719         assertThrows(NullPointerException.class, () -> PropertyUtils.setMappedProperty(bean, "mappedProperty", null, "First Value"));
720         // Use key expression
721         assertThrows(NullPointerException.class, () -> PropertyUtils.setMappedProperty(null, "mappedProperty(First Key)", "First Value"));
722         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.setMappedProperty(bean, "(Second Key)", "Second Value"));
723         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.setMappedProperty(bean, "mappedProperty", "Third Value"));
724     }
725 
726     /**
727      * Positive and negative tests on setMappedProperty valid arguments.
728      */
729     @Test
730     public void testSetMappedValues() throws Exception {
731         Object value = null;
732         // Use explicit key argument
733         value = PropertyUtils.getMappedProperty(bean, "mappedProperty", "Fourth Key");
734         assertNull(value, "Can not find fourth value");
735 
736         PropertyUtils.setMappedProperty(bean, "mappedProperty", "Fourth Key", "Fourth Value");
737 
738         value = PropertyUtils.getMappedProperty(bean, "mappedProperty", "Fourth Key");
739         assertEquals("Fourth Value", value, "Can find fourth value");
740 
741         // Use key expression with parentheses
742         value = PropertyUtils.getMappedProperty(bean, "mappedProperty(Fifth Key)");
743         assertNull(value, "Can not find fifth value");
744 
745         PropertyUtils.setMappedProperty(bean, "mappedProperty(Fifth Key)", "Fifth Value");
746 
747         value = PropertyUtils.getMappedProperty(bean, "mappedProperty(Fifth Key)");
748         assertEquals("Fifth Value", value, "Can find fifth value");
749 
750         // Use key expression with dotted expression
751 
752         value = PropertyUtils.getNestedProperty(bean, "mapProperty.Sixth Key");
753         assertNull(value, "Can not find sixth value");
754 
755         PropertyUtils.setNestedProperty(bean, "mapProperty.Sixth Key", "Sixth Value");
756 
757         value = PropertyUtils.getNestedProperty(bean, "mapProperty.Sixth Key");
758         assertEquals("Sixth Value", value, "Can find sixth value");
759     }
760 
761     /**
762      * Corner cases on setNestedProperty invalid arguments.
763      */
764     @Test
765     public void testSetNestedArguments() {
766         assertThrows(NullPointerException.class, () -> PropertyUtils.setNestedProperty(null, "stringProperty", ""));
767         assertThrows(NullPointerException.class, () -> PropertyUtils.setNestedProperty(bean, null, ""));
768     }
769 
770     /**
771      * Test setNextedProperty on a boolean property.
772      */
773     @Test
774     public void testSetNestedBoolean() throws Exception {
775         final boolean oldValue = nested.getBooleanProperty();
776         final boolean newValue = !oldValue;
777         PropertyUtils.setNestedProperty(bean, "nested.booleanProperty", Boolean.valueOf(newValue));
778         assertEquals(newValue, nested.getBooleanProperty(), "Matched new value");
779     }
780 
781     /**
782      * Test setNestedProperty on a double property.
783      */
784     @Test
785     public void testSetNestedDouble() throws Exception {
786         final double oldValue = nested.getDoubleProperty();
787         final double newValue = oldValue + 1.0;
788         PropertyUtils.setNestedProperty(bean, "nested.doubleProperty", Double.valueOf(newValue));
789         assertEquals(newValue, nested.getDoubleProperty(), 0.005, "Matched new value");
790     }
791 
792     /**
793      * Test setNestedProperty on a float property.
794      */
795     @Test
796     public void testSetNestedFloat() throws Exception {
797         final float oldValue = nested.getFloatProperty();
798         final float newValue = oldValue + (float) 1.0;
799         PropertyUtils.setNestedProperty(bean, "nested.floatProperty", Float.valueOf(newValue));
800         assertEquals(newValue, nested.getFloatProperty(), (float) 0.005, "Matched new value");
801     }
802 
803     /**
804      * Test setNestedProperty on a int property.
805      */
806     @Test
807     public void testSetNestedInt() throws Exception {
808         final int oldValue = nested.getIntProperty();
809         final int newValue = oldValue + 1;
810         PropertyUtils.setNestedProperty(bean, "nested.intProperty", Integer.valueOf(newValue));
811         assertEquals(newValue, nested.getIntProperty(), "Matched new value");
812     }
813 
814     /**
815      * Test setNestedProperty on a long property.
816      */
817     @Test
818     public void testSetNestedLong() throws Exception {
819         final long oldValue = nested.getLongProperty();
820         final long newValue = oldValue + 1;
821         PropertyUtils.setNestedProperty(bean, "nested.longProperty", Long.valueOf(newValue));
822         assertEquals(newValue, nested.getLongProperty(), "Matched new value");
823     }
824 
825     /**
826      * Test setNestedProperty on a read-only String property.
827      */
828     @Test
829     public void testSetNestedReadOnly() throws Exception {
830         assertThrows(NoSuchMethodException.class,
831                 () -> PropertyUtils.setNestedProperty(bean, "nested.readOnlyProperty", nested.getWriteOnlyPropertyValue() + " Extra Value"));
832     }
833 
834     /**
835      * Test setNestedProperty on a short property.
836      */
837     @Test
838     public void testSetNestedShort() throws Exception {
839         final short oldValue = nested.getShortProperty();
840         short newValue = oldValue;
841         newValue++;
842         PropertyUtils.setNestedProperty(bean, "nested.shortProperty", Short.valueOf(newValue));
843         assertEquals(newValue, nested.getShortProperty(), "Matched new value");
844     }
845 
846     /**
847      * Test setNestedProperty on a String property.
848      */
849     @Test
850     public void testSetNestedString() throws Exception {
851         final String oldValue = nested.getStringProperty();
852         final String newValue = oldValue + " Extra Value";
853         PropertyUtils.setNestedProperty(bean, "nested.stringProperty", newValue);
854         assertEquals(newValue, nested.getStringProperty(), "Matched new value");
855     }
856 
857     /**
858      * Test setNestedProperty on an unknown property name.
859      */
860     @Test
861     public void testSetNestedUnknown() throws Exception {
862         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.setNestedProperty(bean, "nested.unknown", "New String Value"));
863     }
864 
865     /**
866      * Test setNestedProperty on a write-only String property.
867      */
868     @Test
869     public void testSetNestedWriteOnly() throws Exception {
870         final String oldValue = nested.getWriteOnlyPropertyValue();
871         final String newValue = oldValue + " Extra Value";
872         PropertyUtils.setNestedProperty(bean, "nested.writeOnlyProperty", newValue);
873         assertEquals(newValue, nested.getWriteOnlyPropertyValue(), "Matched new value");
874     }
875 
876     /**
877      * Corner cases on setSimpleProperty invalid arguments.
878      */
879     @Test
880     public void testSetSimpleArguments() {
881         assertThrows(NullPointerException.class, () -> PropertyUtils.setSimpleProperty(null, "stringProperty", ""));
882         assertThrows(NullPointerException.class, () -> PropertyUtils.setSimpleProperty(bean, null, ""));
883     }
884 
885     /**
886      * Test setSimpleProperty on a boolean property.
887      */
888     @Test
889     public void testSetSimpleBoolean() throws Exception {
890         final boolean oldValue = ((Boolean) bean.get("booleanProperty")).booleanValue();
891         final boolean newValue = !oldValue;
892         PropertyUtils.setSimpleProperty(bean, "booleanProperty", Boolean.valueOf(newValue));
893         assertEquals(newValue, ((Boolean) bean.get("booleanProperty")).booleanValue(), "Matched new value");
894     }
895 
896     /**
897      * Test setSimpleProperty on a double property.
898      */
899     @Test
900     public void testSetSimpleDouble() throws Exception {
901         final double oldValue = ((Double) bean.get("doubleProperty")).doubleValue();
902         final double newValue = oldValue + 1.0;
903         PropertyUtils.setSimpleProperty(bean, "doubleProperty", Double.valueOf(newValue));
904         assertEquals(newValue, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005, "Matched new value");
905     }
906 
907     /**
908      * Test setSimpleProperty on a float property.
909      */
910     @Test
911     public void testSetSimpleFloat() throws Exception {
912         final float oldValue = ((Float) bean.get("floatProperty")).floatValue();
913         final float newValue = oldValue + (float) 1.0;
914         PropertyUtils.setSimpleProperty(bean, "floatProperty", Float.valueOf(newValue));
915         assertEquals(newValue, ((Float) bean.get("floatProperty")).floatValue(), (float) 0.005, "Matched new value");
916     }
917 
918     /**
919      * Negative test setSimpleProperty on an indexed property.
920      */
921     @Test
922     public void testSetSimpleIndexed() throws Exception {
923         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.setSimpleProperty(bean, "stringIndexed[0]", "New String Value"));
924     }
925 
926     /**
927      * Test setSimpleProperty on a int property.
928      */
929     @Test
930     public void testSetSimpleInt() throws Exception {
931         final int oldValue = ((Integer) bean.get("intProperty")).intValue();
932         final int newValue = oldValue + 1;
933         PropertyUtils.setSimpleProperty(bean, "intProperty", Integer.valueOf(newValue));
934         assertEquals(newValue, ((Integer) bean.get("intProperty")).intValue(), "Matched new value");
935     }
936 
937     /**
938      * Test setSimpleProperty on a long property.
939      */
940     @Test
941     public void testSetSimpleLong() throws Exception {
942         final long oldValue = ((Long) bean.get("longProperty")).longValue();
943         final long newValue = oldValue + 1;
944         PropertyUtils.setSimpleProperty(bean, "longProperty", Long.valueOf(newValue));
945         assertEquals(newValue, ((Long) bean.get("longProperty")).longValue(), "Matched new value");
946     }
947 
948     /**
949      * Negative test setSimpleProperty on a nested property.
950      */
951     @Test
952     public void testSetSimpleNested() throws Exception {
953         assertThrows(IllegalArgumentException.class, () -> PropertyUtils.setSimpleProperty(bean, "nested.stringProperty", "New String Value"));
954     }
955 
956     /**
957      * Test setSimpleProperty on a short property.
958      */
959     @Test
960     public void testSetSimpleShort() throws Exception {
961         final short oldValue = ((Short) bean.get("shortProperty")).shortValue();
962         short newValue = oldValue;
963         newValue++;
964         PropertyUtils.setSimpleProperty(bean, "shortProperty", Short.valueOf(newValue));
965         assertEquals(newValue, ((Short) bean.get("shortProperty")).shortValue(), "Matched new value");
966     }
967 
968     /**
969      * Test setSimpleProperty on a String property.
970      */
971     @Test
972     public void testSetSimpleString() throws Exception {
973         final String oldValue = (String) bean.get("stringProperty");
974         final String newValue = oldValue + " Extra Value";
975         PropertyUtils.setSimpleProperty(bean, "stringProperty", newValue);
976         assertEquals(newValue, (String) bean.get("stringProperty"), "Matched new value");
977     }
978 
979     /**
980      * Test setSimpleProperty on an unknown property name.
981      */
982     @Test
983     public void testSetSimpleUnknown() throws Exception {
984         assertThrows(NoSuchMethodException.class, () -> PropertyUtils.setSimpleProperty(bean, "unknown", "New String Value"));
985     }
986 
987 }