View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.beanutils;
18  
19  import java.io.OutputStream;
20  import java.io.PrintStream;
21  import java.lang.reflect.Method;
22  import java.lang.reflect.Modifier;
23  
24  import junit.framework.Test;
25  import junit.framework.TestCase;
26  import junit.framework.TestSuite;
27  
28  import org.apache.commons.beanutils.priv.PrivateBeanFactory;
29  import org.apache.commons.beanutils.priv.PublicSubBean;
30  
31  /**
32   * <p> Test case for <code>MethodUtils</code> </p>
33   *
34   * @version $Id$
35   */
36  public class MethodUtilsTestCase extends TestCase {
37  
38      // ---------------------------------------------------------- Constructors
39  
40      /**
41       * Construct a new instance of this test case.
42       *
43       * @param name Name of the test case
44       */
45      public MethodUtilsTestCase(final String name) {
46          super(name);
47      }
48  
49  
50      // -------------------------------------------------- Overall Test Methods
51  
52  
53      /**
54       * Set up instance variables required by this test case.
55       */
56      @Override
57      public void setUp() {
58      }
59  
60  
61      /**
62       * Return the tests included in this test suite.
63       */
64      public static Test suite() {
65          return (new TestSuite(MethodUtilsTestCase.class));
66      }
67  
68      /**
69       * Tear down instance variables required by this test case.
70       */
71      @Override
72      public void tearDown() {
73      }
74  
75  
76      // ------------------------------------------------ Individual Test Methods
77  
78      /**
79       * <p> Test <code>getAccessibleMethod</code>.
80       */
81      public void testGetAccessibleMethod() {
82          // easy bit first - find a public method
83          final Method method = MethodUtils.getAccessibleMethod
84                  (TestBean.class, "setStringProperty", String.class);
85  
86          assertMethod(method, "setStringProperty");
87      }
88  
89      public void testGetAccessibleMethodFromInterface() {
90          Method method;
91          // trickier this one - find a method in a direct interface
92          method = MethodUtils.getAccessibleMethod
93                  (PrivateBeanFactory.create().getClass(),
94                          "methodBar",
95                          String.class);
96  
97          assertMethod(method, "methodBar");
98      }
99  
100 
101     public void testGetAccessibleMethodIndirectInterface() {
102         Method method;
103         // trickier this one - find a method in a indirect interface
104         method = MethodUtils.getAccessibleMethod
105                 (PrivateBeanFactory.createSubclass().getClass(),
106                         "methodBaz",
107                         String.class);
108 
109         assertMethod(method, "methodBaz");
110     }
111 
112     private static void assertMethod(final Method method, final String methodName) {
113         assertNotNull(method);
114         assertEquals("Method is not named correctly", methodName,
115                 method.getName());
116         assertTrue("Method is not public",
117                 Modifier.isPublic(method.getModifiers()));
118     }
119 
120     /**
121      * <p> Test <code>invokeExactMethod</code>.
122      */
123     public void testInvokeExactMethod() throws Exception {
124             final TestBean bean = new TestBean();
125             final Object ret = MethodUtils.invokeExactMethod(bean, "setStringProperty", "TEST");
126 
127             assertNull(ret);
128             assertEquals("Method ONE was invoked", "TEST", bean.getStringProperty());
129     }
130 
131     public void testInvokeExactMethodFromInterface() throws Exception {
132         final Object ret = MethodUtils.invokeExactMethod(
133                 PrivateBeanFactory.create(),
134                 "methodBar",
135                 "ANOTHER TEST");
136 
137         assertEquals("Method TWO wasn't invoked correctly", "ANOTHER TEST", ret);
138     }
139 
140     public void testInvokeExactMethodIndirectInterface() throws Exception {
141         final Object ret = MethodUtils.invokeExactMethod(
142                 PrivateBeanFactory.createSubclass(),
143                 "methodBaz",
144                 "YET ANOTHER TEST");
145 
146         assertEquals("Method TWO was invoked correctly", "YET ANOTHER TEST", ret);
147     }
148 
149 
150     public void testInvokeExactMethodNullArray() throws Exception {
151         final Object result = MethodUtils.invokeExactMethod(
152                 new AlphaBean("parent"),
153                 "getName",
154                 null);
155         assertEquals("parent", result);
156     }
157 
158     public void testInvokeExactMethodNullArrayNullArray() throws Exception {
159         final Object result = MethodUtils.invokeExactMethod(
160                 new AlphaBean("parent"),
161                 "getName",
162                 null,
163                 null);
164 
165         assertEquals("parent", result);
166     }
167 
168     public void testInvokeExactMethodNull() throws Exception {
169         final Object object = new Object();
170         final Object result = MethodUtils.invokeExactMethod(object, "toString", (Object) null);
171         assertEquals(object.toString(), result);
172     }
173 
174     /**
175      * <p> Test <code>invokeMethod</code>.
176      */
177     public void testInvokeMethod() throws Exception {
178         final AbstractParent parent = new AlphaBean("parent");
179         final BetaBean childOne = new BetaBean("ChildOne");
180 
181         assertEquals(
182                         "Cannot invoke through abstract class (1)",
183                         "ChildOne",
184                         MethodUtils.invokeMethod(parent, "testAddChild", childOne));
185     }
186 
187     public void testInvokeMethodObject() throws Exception {
188         final AbstractParent parent = new AlphaBean("parent");
189         final Child childTwo = new AlphaBean("ChildTwo");
190 
191         assertEquals("Cannot invoke through interface (1)",
192                         "ChildTwo",
193                         MethodUtils.invokeMethod(parent, "testAddChild", childTwo));
194     }
195 
196     public void testInvokeMethodArray() throws Exception {
197         final AbstractParent parent = new AlphaBean("parent");
198         final AlphaBean childTwo = new AlphaBean("ChildTwo");
199 
200         final Object[] params = new Object[2];
201         params[0] = "parameter";
202         params[1] = childTwo;
203 
204         assertEquals("Cannot invoke through abstract class",
205                         "ChildTwo",
206                         MethodUtils.invokeMethod(parent, "testAddChild2", params));
207     }
208 
209 
210     public void testInvokeMethodUnknown() throws Exception {
211         // test that exception is correctly thrown when a method cannot be found with matching params
212         try {
213             final AbstractParent parent = new AlphaBean("parent");
214             final BetaBean childOne = new BetaBean("ChildOne");
215             MethodUtils.invokeMethod(parent, "bogus", childOne);
216 
217             fail("No exception thrown when no appropriate method exists");
218         } catch (final NoSuchMethodException expected) {
219             // this is what we're expecting!
220         }
221     }
222 
223     public void testInvokeMethodNullArray() throws Exception {
224         final Object result = MethodUtils.invokeMethod(
225                 new AlphaBean("parent"),
226                 "getName",
227                 null);
228 
229         assertEquals("parent", result);
230     }
231 
232     public void testInvokeMethodNullArrayNullArray() throws Exception {
233         final Object result = MethodUtils.invokeMethod(
234                 new AlphaBean("parent"),
235                 "getName",
236                 null,
237                 null);
238 
239         assertEquals("parent", result);
240     }
241 
242     public void testInvokeMethodNull() throws Exception {
243         final Object object = new Object();
244         final Object result = MethodUtils.invokeMethod(object, "toString", (Object) null);
245         assertEquals(object.toString(), result);
246     }
247 
248     public void testInvokeMethodPrimitiveBoolean() throws Exception {
249         final PrimitiveBean bean = new PrimitiveBean();
250         MethodUtils.invokeMethod(bean, "setBoolean", Boolean.FALSE);
251         assertEquals("Call boolean property using invokeMethod", false, bean.getBoolean());
252     }
253 
254     public void testInvokeMethodPrimitiveFloat() throws Exception {
255         final PrimitiveBean bean = new PrimitiveBean();
256         MethodUtils.invokeMethod(bean, "setFloat", Float.valueOf(20.0f));
257         assertEquals("Call float property using invokeMethod", 20.0f, bean.getFloat(), 0.01f);
258     }
259 
260     public void testInvokeMethodPrimitiveLong() throws Exception {
261         final PrimitiveBean bean = new PrimitiveBean();
262         MethodUtils.invokeMethod(bean, "setLong", Long.valueOf(10));
263         assertEquals("Call long property using invokeMethod", 10, bean.getLong());
264     }
265 
266     public void testInvokeMethodPrimitiveInt() throws Exception {
267         final PrimitiveBean bean = new PrimitiveBean();
268         MethodUtils.invokeMethod(bean, "setInt", Integer.valueOf(12));
269         assertEquals("Set int property using invokeMethod", 12, bean.getInt());
270     }
271 
272     public void testInvokeMethodPrimitiveDouble() throws Exception {
273         final PrimitiveBean bean = new PrimitiveBean();
274         MethodUtils.invokeMethod(bean, "setDouble", Double.valueOf(25.5d));
275         assertEquals("Set double property using invokeMethod", 25.5d, bean.getDouble(), 0.01d);
276     }
277 
278     public void testStaticInvokeMethod() throws Exception {
279 
280         Object value = null;
281         int current = TestBean.currentCounter();
282 
283         value = MethodUtils.invokeStaticMethod(TestBean.class, "currentCounter", new Object[0]);
284         assertEquals("currentCounter value", current, ((Integer) value).intValue());
285 
286         MethodUtils.invokeStaticMethod(TestBean.class, "incrementCounter", new Object[0]);
287         current++;
288 
289         value = MethodUtils.invokeStaticMethod(TestBean.class, "currentCounter", new Object[0]);
290         assertEquals("currentCounter value", current, ((Integer) value).intValue());
291 
292         MethodUtils.invokeStaticMethod(TestBean.class, "incrementCounter", new Object[] { new Integer(8) } );
293         current += 8;
294 
295         value = MethodUtils.invokeStaticMethod(TestBean.class, "currentCounter", new Object[0]);
296         assertEquals("currentCounter value", current, ((Integer) value).intValue());
297 
298         MethodUtils.invokeExactStaticMethod(TestBean.class, "incrementCounter",
299             new Object[] { new Integer(8) }, new Class[] { Number.class } );
300         current += 16;
301 
302         value = MethodUtils.invokeStaticMethod(TestBean.class, "currentCounter", new Object[0]);
303         assertEquals("currentCounter value", current, ((Integer) value).intValue());
304     }
305 
306     public void testInvokeStaticMethodNull() throws Exception {
307         final int current = TestBean.currentCounter();
308         final Object value = MethodUtils.invokeStaticMethod(TestBean.class, "currentCounter", (Object) null);
309         assertEquals("currentCounter value", current, ((Integer) value).intValue());
310     }
311 
312     public void testInvokeExactStaticMethodNull() throws Exception {
313         final int current = TestBean.currentCounter();
314         final Object value = MethodUtils.invokeExactStaticMethod(TestBean.class, "currentCounter", (Object) null);
315         assertEquals("currentCounter value", current, ((Integer) value).intValue());
316     }
317 
318     /**
319      * Simple tests for accessing static methods via invokeMethod().
320      */
321     public void testSimpleStatic1() {
322 
323         final TestBean bean = new TestBean();
324         Object value = null;
325         int current = TestBean.currentCounter();
326 
327         try {
328 
329             // Return initial value of the counter
330             value = MethodUtils.invokeMethod
331                 (bean, "currentCounter", new Object[0], new Class[0]);
332             assertNotNull("currentCounter exists", value);
333             assertTrue("currentCounter type",
334                        value instanceof Integer);
335             assertEquals("currentCounter value",
336                          current,
337                          ((Integer) value).intValue());
338 
339             // Increment via no-arguments version
340             MethodUtils.invokeMethod
341                 (bean, "incrementCounter", new Object[0], new Class[0]);
342 
343             // Validate updated value
344             current++;
345             value = MethodUtils.invokeMethod
346                 (bean, "currentCounter", new Object[0], new Class[0]);
347             assertNotNull("currentCounter exists", value);
348             assertTrue("currentCounter type",
349                        value instanceof Integer);
350             assertEquals("currentCounter value",
351                          current,
352                          ((Integer) value).intValue());
353 
354             // Increment via specified-argument version
355             MethodUtils.invokeMethod
356                 (bean, "incrementCounter",
357                  new Object[] { new Integer(5) },
358                  new Class[] { Integer.TYPE });
359 
360             // Validate updated value
361             current += 5;
362             value = MethodUtils.invokeMethod
363                 (bean, "currentCounter", new Object[0], new Class[0]);
364             assertNotNull("currentCounter exists", value);
365             assertTrue("currentCounter type",
366                        value instanceof Integer);
367             assertEquals("currentCounter value",
368                          current,
369                          ((Integer) value).intValue());
370 
371         } catch (final Exception e) {
372             fail("Threw exception" + e);
373         }
374 
375     }
376 
377 
378     /**
379      * Simple tests for accessing static methods via invokeExactMethod().
380      */
381     public void testSimpleStatic2() {
382 
383         final TestBean bean = new TestBean();
384         Object value = null;
385         int current = TestBean.currentCounter();
386 
387         try {
388 
389             // Return initial value of the counter
390             value = MethodUtils.invokeExactMethod
391                 (bean, "currentCounter", new Object[0], new Class[0]);
392             assertNotNull("currentCounter exists", value);
393             assertTrue("currentCounter type",
394                        value instanceof Integer);
395             assertEquals("currentCounter value",
396                          current,
397                          ((Integer) value).intValue());
398 
399             // Increment via no-arguments version
400             MethodUtils.invokeExactMethod
401                 (bean, "incrementCounter", new Object[0], new Class[0]);
402 
403             // Validate updated value
404             current++;
405             value = MethodUtils.invokeExactMethod
406                 (bean, "currentCounter", new Object[0], new Class[0]);
407             assertNotNull("currentCounter exists", value);
408             assertTrue("currentCounter type",
409                        value instanceof Integer);
410             assertEquals("currentCounter value",
411                          current,
412                          ((Integer) value).intValue());
413 
414             // Increment via specified-argument version
415             MethodUtils.invokeExactMethod
416                 (bean, "incrementCounter",
417                  new Object[] { new Integer(5) },
418                  new Class[] { Integer.TYPE });
419 
420             // Validate updated value
421             current += 5;
422             value = MethodUtils.invokeExactMethod
423                 (bean, "currentCounter", new Object[0], new Class[0]);
424             assertNotNull("currentCounter exists", value);
425             assertTrue("currentCounter type",
426                        value instanceof Integer);
427             assertEquals("currentCounter value",
428                          current,
429                          ((Integer) value).intValue());
430 
431         } catch (final Exception e) {
432             fail("Threw exception" + e);
433         }
434 
435     }
436 
437     /**
438      * Simple tests for accessing static methods via getAccessibleMethod()
439      */
440     public void testSimpleStatic3() {
441 
442         Object value = null;
443         int current = TestBean.currentCounter();
444 
445         try {
446 
447             // Acquire the methods we need
448             final Method currentCounterMethod = MethodUtils.getAccessibleMethod
449                 (TestBean.class, "currentCounter",
450                  new Class[0]);
451             assertNotNull("currentCounterMethod exists",
452                           currentCounterMethod);
453             assertEquals("currentCounterMethod name",
454                          "currentCounter",
455                          currentCounterMethod.getName());
456             assertEquals("currentCounterMethod args",
457                          0,
458                          currentCounterMethod.getParameterTypes().length);
459             assertTrue("currentCounterMethod public",
460                        Modifier.isPublic(currentCounterMethod.getModifiers()));
461             assertTrue("currentCounterMethod static",
462                        Modifier.isStatic(currentCounterMethod.getModifiers()));
463             final Method incrementCounterMethod1 = MethodUtils.getAccessibleMethod
464                 (TestBean.class, "incrementCounter",
465                  new Class[0]);
466             assertNotNull("incrementCounterMethod1 exists",
467                           incrementCounterMethod1);
468             assertEquals("incrementCounterMethod1 name",
469                          "incrementCounter",
470                          incrementCounterMethod1.getName());
471             assertEquals("incrementCounterMethod1 args",
472                          0,
473                          incrementCounterMethod1.getParameterTypes().length);
474             assertTrue("incrementCounterMethod1 public",
475                        Modifier.isPublic(incrementCounterMethod1.getModifiers()));
476             assertTrue("incrementCounterMethod1 static",
477                        Modifier.isStatic(incrementCounterMethod1.getModifiers()));
478             final Method incrementCounterMethod2 = MethodUtils.getAccessibleMethod
479                 (TestBean.class, "incrementCounter",
480                  new Class[] { Integer.TYPE });
481             assertNotNull("incrementCounterMethod2 exists",
482                           incrementCounterMethod2);
483             assertEquals("incrementCounterMethod2 name",
484                          "incrementCounter",
485                          incrementCounterMethod2.getName());
486             assertEquals("incrementCounterMethod2 args",
487                          1,
488                          incrementCounterMethod2.getParameterTypes().length);
489             assertTrue("incrementCounterMethod2 public",
490                        Modifier.isPublic(incrementCounterMethod2.getModifiers()));
491             assertTrue("incrementCounterMethod2 static",
492                        Modifier.isStatic(incrementCounterMethod2.getModifiers()));
493 
494             // Return initial value of the counter
495             value = currentCounterMethod.invoke(null, new Object[0]);
496             assertNotNull("currentCounter exists", value);
497             assertTrue("currentCounter type",
498                        value instanceof Integer);
499             assertEquals("currentCounter value",
500                          current,
501                          ((Integer) value).intValue());
502 
503             // Increment via no-arguments version
504             incrementCounterMethod1.invoke(null, new Object[0]);
505 
506             // Validate updated value
507             current++;
508             value = currentCounterMethod.invoke(null, new Object[0]);
509             assertNotNull("currentCounter exists", value);
510             assertTrue("currentCounter type",
511                        value instanceof Integer);
512             assertEquals("currentCounter value",
513                          current,
514                          ((Integer) value).intValue());
515 
516             // Increment via specified-argument version
517             incrementCounterMethod2.invoke(null,
518                                            new Object[] { new Integer(5) });
519 
520             // Validate updated value
521             current += 5;
522             value = currentCounterMethod.invoke(null, new Object[0]);
523             assertNotNull("currentCounter exists", value);
524             assertTrue("currentCounter type",
525                        value instanceof Integer);
526             assertEquals("currentCounter value",
527                          current,
528                          ((Integer) value).intValue());
529 
530         } catch (final Exception e) {
531             fail("Threw exception" + e);
532         }
533 
534     }
535 
536     public void testPublicSub() throws Exception {
537         // make sure that bean does what it should
538         final PublicSubBean bean = new PublicSubBean();
539         assertEquals("Start value (foo)", bean.getFoo(), "This is foo");
540         assertEquals("Start value (bar)", bean.getBar(), "This is bar");
541         bean.setFoo("new foo");
542         bean.setBar("new bar");
543         assertEquals("Set value (foo)", bean.getFoo(), "new foo");
544         assertEquals("Set value (bar)", bean.getBar(), "new bar");
545 
546         // see if we can access public methods in a default access superclass
547         // from a public access subclass instance
548         MethodUtils.invokeMethod(bean, "setFoo", "alpha");
549         assertEquals("Set value (foo:2)", bean.getFoo(), "alpha");
550         MethodUtils.invokeMethod(bean, "setBar", "beta");
551         assertEquals("Set value (bar:2)", bean.getBar(), "beta");
552 
553         Method method = null;
554         try {
555             method = MethodUtils.getAccessibleMethod(PublicSubBean.class, "setFoo", String.class);
556         } catch (final Throwable t) {
557             fail("getAccessibleMethod() setFoo threw " + t);
558         }
559         assertNotNull("getAccessibleMethod() setFoo is Null", method);
560         try {
561             method.invoke(bean, new Object[] {"1111"});
562         } catch (final Throwable t) {
563             fail("Invoking setFoo threw " + t);
564         }
565         assertEquals("Set value (foo:3)", "1111", bean.getFoo());
566 
567         try {
568             method = MethodUtils.getAccessibleMethod(PublicSubBean.class, "setBar", String.class);
569         } catch (final Throwable t) {
570             fail("getAccessibleMethod() setBar threw " + t);
571         }
572         assertNotNull("getAccessibleMethod() setBar is Null", method);
573         try {
574             method.invoke(bean, new Object[] {"2222"});
575         } catch (final Throwable t) {
576             fail("Invoking setBar threw " + t);
577         }
578         assertEquals("Set value (bar:3)", "2222", bean.getBar());
579 
580     }
581 
582     public void testParentMethod() throws Exception {
583         final OutputStream os = new PrintStream(System.out);
584         final PrintStream ps = new PrintStream(System.out);
585 
586         A a = new A();
587         MethodUtils.invokeMethod(a, "foo", os);
588         assertTrue("Method Invoked(1)", a.called);
589 
590         a = new A();
591         MethodUtils.invokeMethod(a, "foo", ps);
592         assertTrue("Method Invoked(2)", a.called);
593     }
594 
595     /**
596      * Test {@link MethodUtils#clearCache()}.
597      */
598     public void testClearCache() throws Exception {
599         MethodUtils.clearCache(); // make sure it starts empty
600         final PublicSubBean bean = new PublicSubBean();
601         MethodUtils.invokeMethod(bean, "setFoo", "alpha");
602         assertEquals(1, MethodUtils.clearCache());
603         assertEquals(0, MethodUtils.clearCache());
604     }
605 
606     /**
607      * Test {@link MethodUtils#setCacheMethods(boolean)}.
608      */
609     public void testSetCacheMethods() throws Exception {
610         MethodUtils.setCacheMethods(true);
611         MethodUtils.clearCache(); // make sure it starts empty
612 
613         final PublicSubBean bean = new PublicSubBean();
614         MethodUtils.invokeMethod(bean, "setFoo", "alpha");
615         assertEquals(1, MethodUtils.clearCache());
616         assertEquals(0, MethodUtils.clearCache());
617     }
618 
619     public void testNoCaching() throws Exception {
620         // no caching
621         MethodUtils.setCacheMethods(false);
622 
623         final PublicSubBean bean = new PublicSubBean();
624         MethodUtils.invokeMethod(bean, "setFoo", "alpha");
625         assertEquals(0, MethodUtils.clearCache());
626 
627         // reset default
628         MethodUtils.setCacheMethods(true);
629     }
630 }