1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.digester3;
20
21 import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.StringReader;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.Set;
33
34 import org.apache.commons.digester3.binder.AbstractRulesModule;
35 import org.junit.Test;
36 import org.xml.sax.SAXException;
37
38
39
40
41
42
43
44
45
46 public class CallMethodRuleTestCase
47 {
48
49
50
51
52
53 @Test
54 public void testBasic()
55 throws SAXException, IOException
56 {
57 Digester digester = newLoader( new AbstractRulesModule()
58 {
59
60 @Override
61 protected void configure()
62 {
63 forPattern( "employee" ).createObject().ofType( Employee.class );
64
65 forPattern( "employee" ).callMethod( "toString" ).withParamCount( 0 ).withParamTypes( (Class[]) null )
66 .then()
67 .callMethod( "toString" ).withParamCount( 0 ).withParamTypes( (String[]) null )
68 .then()
69 .callMethod( "toString" ).withParamCount( 0 ).withParamTypes( new Class[] {} )
70 .then()
71 .callMethod( "toString" ).withParamCount( 0 ).withParamTypes( new String[] {} )
72 .then()
73 .callMethod( "toString" );
74 }
75
76 }).newDigester();
77
78
79
80 Employee root1 = digester.parse( getInputStream( "Test5.xml" ) );
81 assertNotNull( root1 );
82 }
83
84
85
86
87 @Test
88 public void testCallMethodOnly()
89 throws Exception
90 {
91 Digester digester = newLoader( new AbstractRulesModule()
92 {
93
94 @Override
95 protected void configure()
96 {
97 forPattern( "employee" ).createObject().ofType( Employee.class );
98 forPattern( "employee/firstName" ).callMethod( "setFirstName" ).usingElementBodyAsArgument();
99 forPattern( "employee/lastName" ).callMethod( "setLastName" ).usingElementBodyAsArgument();
100 }
101
102 }).newDigester();
103
104
105 Employee employee = digester.parse( getInputStream( "Test9.xml" ) );
106 assertNotNull( "parsed an employee", employee );
107
108
109 assertEquals( "Set first name", "First Name", employee.getFirstName() );
110 assertEquals( "Set last name", "Last Name", employee.getLastName() );
111 }
112
113
114
115
116
117 @Test
118 public void testSettingProperties()
119 throws SAXException, IOException
120 {
121 Digester digester = newLoader( new AbstractRulesModule()
122 {
123
124 @Override
125 protected void configure()
126 {
127 forPattern( "employee" ).createObject().ofType( Employee.class )
128 .then()
129 .callMethod( "setLastName" ).withParamTypes( "java.lang.String" );
130 forPattern( "employee/lastName" ).callParam().ofIndex( 0 );
131 }
132
133 }).newDigester();
134
135
136
137
138 Employee employee = digester.parse( getInputStream( "Test5.xml" ) );
139 assertEquals( "Failed to call Employee.setLastName", "Last Name", employee.getLastName() );
140
141 digester = newLoader( new AbstractRulesModule()
142 {
143
144 @Override
145 protected void configure()
146 {
147 forPattern( "employee" ).createObject().ofType( Employee.class )
148 .then()
149 .callMethod( "setAge" ).withParamTypes( int.class );
150 forPattern( "employee/age" ).callParam();
151 }
152
153 }).newDigester();
154
155
156
157 employee = digester.parse( getInputStream( "Test5.xml" ) );
158 assertEquals( "Failed to call Employee.setAge", 21, employee.getAge() );
159
160 digester = newLoader( new AbstractRulesModule()
161 {
162
163 @Override
164 protected void configure()
165 {
166 forPattern( "employee" ).createObject().ofType( Employee.class )
167 .then()
168 .callMethod( "setActive" ).withParamTypes( boolean.class );
169 forPattern( "employee/active" ).callParam();
170 }
171
172 }).newDigester();
173
174
175
176 employee = digester.parse( getInputStream( "Test5.xml" ) );
177 assertEquals( "Failed to call Employee.setActive", true, employee.isActive() );
178
179 digester = newLoader( new AbstractRulesModule()
180 {
181
182 @Override
183 protected void configure()
184 {
185 forPattern( "employee" ).createObject().ofType( Employee.class )
186 .then()
187 .callMethod( "setSalary" ).withParamTypes( float.class );
188 forPattern( "employee/salary" ).callParam();
189 }
190
191 }).newDigester();
192
193
194
195 employee = digester.parse( getInputStream( "Test5.xml" ) );
196 assertEquals( "Failed to call Employee.setSalary", 1000000.0f, employee.getSalary(), 0.1f );
197 }
198
199
200
201
202 @Test
203 public void testParamsFromStack()
204 throws SAXException, IOException
205 {
206 Digester digester = newLoader( new AbstractRulesModule()
207 {
208
209 @Override
210 protected void configure()
211 {
212 forPattern( "map" ).createObject().ofType( HashMap.class )
213 .then()
214 .callMethod( "put" ).withParamCount( 2 );
215 forPattern( "map/key" ).createObject().ofType( AlphaBean.class )
216 .then()
217 .setProperties()
218 .then()
219 .callParam().fromStack( true );
220 forPattern( "map/value" ).createObject().ofType( BetaBean.class )
221 .then()
222 .setProperties()
223 .then()
224 .callParam().ofIndex( 1 ).fromStack( true );
225 }
226
227 }).newDigester();
228
229 StringBuilder xml =
230 new StringBuilder().append( "<?xml version='1.0'?>" ).append( "<map>" ).append( " <key name='The key'/>" ).append( " <value name='The value'/>" ).append( "</map>" );
231
232 HashMap<AlphaBean, BetaBean> map = digester.parse( new StringReader( xml.toString() ) );
233
234 assertNotNull( map );
235 assertEquals( 1, map.size() );
236 assertEquals( "The key", map.keySet().iterator().next().getName() );
237 assertEquals( "The value", map.values().iterator().next().getName() );
238 }
239
240
241
242
243
244
245
246
247 @Test
248 public void testOrderNestedPartA()
249 throws Exception
250 {
251 Digester digester = newLoader( new AbstractRulesModule()
252 {
253
254 @Override
255 protected void configure()
256 {
257
258
259
260
261
262 forPattern( "toplevel/element" ).createObject().ofType( NamedBean.class )
263 .then()
264 .callMethod( "setName" ).withParamCount( 1 );
265 forPattern( "toplevel/element/element/element" ).callParam().ofIndex( 0 ).fromAttribute( "name" );
266 forPattern( "toplevel/element/element" ).createObject().ofType( NamedBean.class );
267 }
268
269 }).newDigester();
270
271
272
273 NamedBean root1 = digester.parse( getInputStream( "Test8.xml" ) );
274
275
276
277
278
279
280
281
282 assertEquals( "Wrong method call order", "C", root1.getName() );
283 }
284
285
286
287
288
289
290
291
292
293 @Test
294 public void testOrderNestedPartB()
295 throws Exception
296 {
297 Digester digester = newLoader( new AbstractRulesModule()
298 {
299
300 @Override
301 protected void configure()
302 {
303 forPattern( "*/element" ).callMethod( "append" ).withParamCount( 1 )
304 .then()
305 .callParam().ofIndex( 0 ).fromAttribute( "name" );
306 }
307
308 }).newDigester();
309
310
311 StringBuilder word = new StringBuilder();
312 digester.push( word );
313
314
315 Object root1 = null;
316 try
317 {
318
319 root1 = digester.parse( getInputStream( "Test8.xml" ) );
320 assertNotNull( root1 );
321 }
322 catch ( Throwable t )
323 {
324
325 fail( "Digester threw Exception: " + t );
326 }
327
328 assertEquals( "Wrong method call order", "CBA", word.toString() );
329 }
330
331 @Test
332 public void testPrimitiveReading()
333 throws Exception
334 {
335 StringReader reader =
336 new StringReader( "<?xml version='1.0' ?><root><bean good='true'/><bean good='false'/><bean/>"
337 + "<beanie bad='Fee Fie Foe Fum' good='true'/><beanie bad='Fee Fie Foe Fum' good='false'/>"
338 + "<beanie bad='Fee Fie Foe Fum'/></root>" );
339
340 Digester digester = new Digester();
341
342
343
344
345
346 digester.addObjectCreate( "root/bean", PrimitiveBean.class );
347 digester.addSetNext( "root/bean", "add" );
348 Class<?>[] params = { Boolean.TYPE };
349 digester.addCallMethod( "root/bean", "setBoolean", 1, params );
350 digester.addCallParam( "root/bean", 0, "good" );
351
352 digester.addObjectCreate( "root/beanie", PrimitiveBean.class );
353 digester.addSetNext( "root/beanie", "add" );
354 Class<?>[] beanieParams = { String.class, Boolean.TYPE };
355 digester.addCallMethod( "root/beanie", "testSetBoolean", 2, beanieParams );
356 digester.addCallParam( "root/beanie", 0, "bad" );
357 digester.addCallParam( "root/beanie", 1, "good" );
358
359 ArrayList<PrimitiveBean> list = new ArrayList<PrimitiveBean>();
360 digester.push( list );
361 digester.parse( reader );
362
363 assertEquals( "Wrong number of beans in list", 6, list.size() );
364 PrimitiveBean bean = list.get( 0 );
365 assertTrue( "Bean 0 property not called", bean.getSetBooleanCalled() );
366 assertEquals( "Bean 0 property incorrect", true, bean.getBoolean() );
367 bean = list.get( 1 );
368 assertTrue( "Bean 1 property not called", bean.getSetBooleanCalled() );
369 assertEquals( "Bean 1 property incorrect", false, bean.getBoolean() );
370 bean = list.get( 2 );
371
372 assertTrue( "Bean 2 property called", !bean.getSetBooleanCalled() );
373 bean = list.get( 3 );
374 assertTrue( "Bean 3 property not called", bean.getSetBooleanCalled() );
375 assertEquals( "Bean 3 property incorrect", true, bean.getBoolean() );
376 bean = list.get( 4 );
377 assertTrue( "Bean 4 property not called", bean.getSetBooleanCalled() );
378 assertEquals( "Bean 4 property incorrect", false, bean.getBoolean() );
379 bean = list.get( 5 );
380 assertTrue( "Bean 5 property not called", bean.getSetBooleanCalled() );
381 assertEquals( "Bean 5 property incorrect", false, bean.getBoolean() );
382 }
383
384 @Test
385 public void testFromStack()
386 throws Exception
387 {
388
389 StringReader reader =
390 new StringReader( "<?xml version='1.0' ?><root><one/><two/><three/><four/><five/></root>" );
391
392 Digester digester = new Digester();
393
394 Class<?>[] params = { String.class };
395
396 digester.addObjectCreate( "root/one", NamedBean.class );
397 digester.addSetNext( "root/one", "add" );
398 digester.addCallMethod( "root/one", "setName", 1, params );
399 digester.addCallParam( "root/one", 0, 2 );
400
401 digester.addObjectCreate( "root/two", NamedBean.class );
402 digester.addSetNext( "root/two", "add" );
403 digester.addCallMethod( "root/two", "setName", 1, params );
404 digester.addCallParam( "root/two", 0, 3 );
405
406 digester.addObjectCreate( "root/three", NamedBean.class );
407 digester.addSetNext( "root/three", "add" );
408 digester.addCallMethod( "root/three", "setName", 1, params );
409 digester.addCallParam( "root/three", 0, 4 );
410
411 digester.addObjectCreate( "root/four", NamedBean.class );
412 digester.addSetNext( "root/four", "add" );
413 digester.addCallMethod( "root/four", "setName", 1, params );
414 digester.addCallParam( "root/four", 0, 5 );
415
416 digester.addObjectCreate( "root/five", NamedBean.class );
417 digester.addSetNext( "root/five", "add" );
418 Class<?>[] newParams = { String.class, String.class };
419 digester.addCallMethod( "root/five", "test", 2, newParams );
420 digester.addCallParam( "root/five", 0, 10 );
421 digester.addCallParam( "root/five", 1, 3 );
422
423
424 digester.push( "That lamb was sure to go." );
425 digester.push( "And everywhere that Mary went," );
426 digester.push( "It's fleece was white as snow." );
427 digester.push( "Mary had a little lamb," );
428
429 ArrayList<NamedBean> list = new ArrayList<NamedBean>();
430 digester.push( list );
431 digester.parse( reader );
432
433 assertEquals( "Wrong number of beans in list", 5, list.size() );
434 NamedBean bean = list.get( 0 );
435 assertEquals( "Parameter not set from stack (1)", "Mary had a little lamb,", bean.getName() );
436 bean = list.get( 1 );
437 assertEquals( "Parameter not set from stack (2)", "It's fleece was white as snow.", bean.getName() );
438 bean = list.get( 2 );
439 assertEquals( "Parameter not set from stack (3)", "And everywhere that Mary went,", bean.getName() );
440 bean = list.get( 3 );
441 assertEquals( "Parameter not set from stack (4)", "That lamb was sure to go.", bean.getName() );
442 bean = list.get( 4 );
443 assertEquals( "Out of stack not set to null", null, bean.getName() );
444 }
445
446 @Test
447 public void testTwoCalls()
448 throws Exception
449 {
450
451 StringReader reader =
452 new StringReader( "<?xml version='1.0' ?><root>" + "<param class='int' coolness='true'>25</param>"
453 + "<param class='long'>50</param>" + "<param class='float' coolness='false'>90</param></root>" );
454
455 Digester digester = new Digester();
456
457
458
459
460 digester.addObjectCreate( "root/param", ParamBean.class );
461 digester.addSetNext( "root/param", "add" );
462 digester.addCallMethod( "root/param", "setThisAndThat", 2 );
463 digester.addCallParam( "root/param", 0, "class" );
464 digester.addCallParam( "root/param", 1 );
465 digester.addCallMethod( "root/param", "setCool", 1, new Class[] { boolean.class } );
466 digester.addCallParam( "root/param", 0, "coolness" );
467
468 ArrayList<ParamBean> list = new ArrayList<ParamBean>();
469 digester.push( list );
470 digester.parse( reader );
471
472 assertEquals( "Wrong number of objects created", 3, list.size() );
473 ParamBean bean = list.get( 0 );
474 assertEquals( "Coolness wrong (1)", true, bean.isCool() );
475 assertEquals( "This wrong (1)", "int", bean.getThis() );
476 assertEquals( "That wrong (1)", "25", bean.getThat() );
477 bean = list.get( 1 );
478 assertEquals( "Coolness wrong (2)", false, bean.isCool() );
479 assertEquals( "This wrong (2)", "long", bean.getThis() );
480 assertEquals( "That wrong (2)", "50", bean.getThat() );
481 bean = list.get( 2 );
482 assertEquals( "Coolness wrong (3)", false, bean.isCool() );
483 assertEquals( "This wrong (3)", "float", bean.getThis() );
484 assertEquals( "That wrong (3)", "90", bean.getThat() );
485 }
486
487 @Test
488 public void testNestedBody()
489 throws Exception
490 {
491
492 StringReader reader =
493 new StringReader( "<?xml version='1.0' ?><root>" + "<spam>Simple</spam>"
494 + "<spam>Complex<spam>Deep<spam>Deeper<spam>Deepest</spam></spam></spam></spam>" + "</root>" );
495
496 Digester digester = new Digester();
497
498
499
500
501
502 digester.addObjectCreate( "root/spam", NamedBean.class );
503 digester.addSetRoot( "root/spam", "add" );
504 digester.addCallMethod( "root/spam", "setName", 1 );
505 digester.addCallParam( "root/spam", 0 );
506
507 digester.addObjectCreate( "root/spam/spam", NamedBean.class );
508 digester.addSetRoot( "root/spam/spam", "add" );
509 digester.addCallMethod( "root/spam/spam", "setName", 1 );
510 digester.addCallParam( "root/spam/spam", 0 );
511
512 digester.addObjectCreate( "root/spam/spam/spam", NamedBean.class );
513 digester.addSetRoot( "root/spam/spam/spam", "add" );
514 digester.addCallMethod( "root/spam/spam/spam", "setName", 1 );
515 digester.addCallParam( "root/spam/spam/spam", 0 );
516
517 digester.addObjectCreate( "root/spam/spam/spam/spam", NamedBean.class );
518 digester.addSetRoot( "root/spam/spam/spam/spam", "add" );
519 digester.addCallMethod( "root/spam/spam/spam/spam", "setName", 1 );
520 digester.addCallParam( "root/spam/spam/spam/spam", 0 );
521
522 ArrayList<NamedBean> list = new ArrayList<NamedBean>();
523 digester.push( list );
524 digester.parse( reader );
525
526 NamedBean bean = list.get( 0 );
527 assertEquals( "Wrong name (1)", "Simple", bean.getName() );
528
529 bean = list.get( 4 );
530 assertEquals( "Wrong name (2)", "Complex", bean.getName() );
531 bean = list.get( 3 );
532 assertEquals( "Wrong name (3)", "Deep", bean.getName() );
533 bean = list.get( 2 );
534 assertEquals( "Wrong name (4)", "Deeper", bean.getName() );
535 bean = list.get( 1 );
536 assertEquals( "Wrong name (5)", "Deepest", bean.getName() );
537 }
538
539 @Test
540 public void testProcessingHook()
541 throws Exception
542 {
543
544 class TestCallMethodRule
545 extends CallMethodRule
546 {
547 Object result;
548
549 TestCallMethodRule( String methodName, int paramCount )
550 {
551 super( methodName, paramCount );
552 }
553
554 @Override
555 protected void processMethodCallResult( Object result )
556 {
557 this.result = result;
558 }
559 }
560
561 StringReader reader =
562 new StringReader( "<?xml version='1.0' ?><root>"
563 + "<param class='float' coolness='false'>90</param></root>" );
564
565 Digester digester = new Digester();
566
567
568
569
570 digester.addObjectCreate( "root/param", ParamBean.class );
571 digester.addSetNext( "root/param", "add" );
572 TestCallMethodRule rule = new TestCallMethodRule( "setThisAndThat", 2 );
573 digester.addRule( "root/param", rule );
574 digester.addCallParam( "root/param", 0, "class" );
575 digester.addCallParam( "root/param", 1, "coolness" );
576
577 ArrayList<ParamBean> list = new ArrayList<ParamBean>();
578 digester.push( list );
579 digester.parse( reader );
580
581 assertEquals( "Wrong number of objects created", 1, list.size() );
582 assertEquals( "Result not passed into hook", "The Other", rule.result );
583 }
584
585
586 @Test
587 public void testPathCallParam()
588 throws Exception
589 {
590 String xml =
591 "<?xml version='1.0'?><main>" + "<alpha><beta>Ignore this</beta></alpha>"
592 + "<beta><epsilon><gamma>Ignore that</gamma></epsilon></beta>" + "</main>";
593
594 SimpleTestBean bean = new SimpleTestBean();
595 bean.setAlphaBeta( "[UNSET]", "[UNSET]" );
596
597 StringReader in = new StringReader( xml );
598 Digester digester = new Digester();
599 digester.setRules( new ExtendedBaseRules() );
600 digester.addCallParamPath( "*/alpha/?", 0 );
601 digester.addCallParamPath( "*/epsilon/?", 1 );
602 digester.addCallMethod( "main", "setAlphaBeta", 2 );
603
604 digester.push( bean );
605
606 digester.parse( in );
607
608 assertEquals( "Test alpha property setting", "main/alpha/beta", bean.getAlpha() );
609 assertEquals( "Test beta property setting", "main/beta/epsilon/gamma", bean.getBeta() );
610 }
611
612
613
614
615 @Test
616 public void testCallInvalidTarget()
617 throws Exception
618 {
619
620 Digester digester = new Digester();
621 digester.addObjectCreate( "employee", HashMap.class );
622
623
624
625
626 CallMethodRule r = new CallMethodRule( 1, "put", 0 );
627 digester.addRule( "employee", r );
628
629 try
630 {
631 digester.parse( getInputStream( "Test5.xml" ) );
632 fail( "Exception should be thrown for invalid target offset" );
633 }
634 catch ( SAXException e )
635 {
636
637 }
638 }
639
640
641
642
643 @Test
644 public void testCallNext()
645 throws Exception
646 {
647
648 Digester digester = new Digester();
649 digester.addObjectCreate( "employee", HashMap.class );
650
651 digester.addObjectCreate( "employee/address", Address.class );
652 digester.addSetNestedProperties( "employee/address" );
653 CallMethodRule r = new CallMethodRule( 1, "put", 2 );
654 digester.addRule( "employee/address", r );
655 digester.addCallParam( "employee/address/type", 0 );
656 digester.addCallParam( "employee/address", 1, 0 );
657
658 HashMap<String, Address> map = digester.parse( getInputStream( "Test5.xml" ) );
659
660 assertNotNull( map );
661 Set<String> keys = map.keySet();
662 assertEquals( 2, keys.size() );
663 Address home = map.get( "home" );
664 assertNotNull( home );
665 assertEquals( "HmZip", home.getZipCode() );
666 Address office = map.get( "office" );
667 assertNotNull( office );
668 assertEquals( "OfZip", office.getZipCode() );
669 }
670
671
672
673
674 @Test
675 public void testCallRoot()
676 throws Exception
677 {
678
679 Digester digester = new Digester();
680 digester.addObjectCreate( "employee", HashMap.class );
681
682 digester.addObjectCreate( "employee/address", Address.class );
683 digester.addSetNestedProperties( "employee/address" );
684 CallMethodRule r = new CallMethodRule( -1, "put", 2 );
685 digester.addRule( "employee/address", r );
686 digester.addCallParam( "employee/address/type", 0 );
687 digester.addCallParam( "employee/address", 1, 0 );
688
689 HashMap<String, Address> map = digester.parse( getInputStream( "Test5.xml" ) );
690
691 assertNotNull( map );
692 Set<String> keys = map.keySet();
693 assertEquals( 2, keys.size() );
694 Address home = map.get( "home" );
695 assertNotNull( home );
696 assertEquals( "HmZip", home.getZipCode() );
697 Address office = map.get( "office" );
698 assertNotNull( office );
699 assertEquals( "OfZip", office.getZipCode() );
700 }
701
702
703
704
705
706
707
708
709
710 protected InputStream getInputStream( String name )
711 throws IOException
712 {
713
714 return ( this.getClass().getResourceAsStream( "/org/apache/commons/digester3/" + name ) );
715
716 }
717
718 }