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