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.betwixt;
18  
19  import java.io.FileInputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.StringReader;
23  import java.io.StringWriter;
24  import java.math.BigDecimal;
25  import java.math.BigInteger;
26  import java.sql.Date;
27  import java.sql.Time;
28  import java.sql.Timestamp;
29  import java.text.ParseException;
30  import java.text.SimpleDateFormat;
31  import java.util.ArrayList;
32  import java.util.Calendar;
33  import java.util.List;
34  
35  import junit.framework.Test;
36  import junit.framework.TestSuite;
37  import junit.textui.TestRunner;
38  
39  import org.apache.commons.beanutils.ConversionException;
40  import org.apache.commons.beanutils.ConvertUtils;
41  import org.apache.commons.beanutils.Converter;
42  import org.apache.commons.betwixt.io.BeanReader;
43  import org.apache.commons.betwixt.io.BeanWriter;
44  import org.apache.commons.betwixt.strategy.ConvertUtilsObjectStringConverter;
45  import org.apache.commons.betwixt.strategy.HyphenatedNameMapper;
46  import org.apache.commons.collections.CollectionUtils;
47  import org.apache.commons.digester.ExtendedBaseRules;
48  import org.apache.commons.digester.Rule;
49  import org.xml.sax.Attributes;
50  
51  
52  /*** Test harness for the BeanReader
53    *
54    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
55    * @version $Revision: 1.7 $
56    */
57  public class TestBeanReader extends AbstractTestCase {
58      
59      public static void main( String[] args ) {
60          TestRunner.run( suite() );
61      }
62      
63      public static Test suite() {
64          return new TestSuite(TestBeanReader.class);
65      }
66      
67      public TestBeanReader(String testName) {
68          super(testName);
69      }
70      
71      public void testBeanWriter() throws Exception {
72          BeanReader reader = new BeanReader();
73          reader.registerBeanClass( getBeanClass() );
74  
75          InputStream in = getXMLInput();
76          try {
77              Object bean = reader.parse( in );
78  
79              testCustomer(bean);
80              
81              String out = writeBean( bean );
82              String xml = "<?xml version='1.0'?><CustomerBean><name>James</name><time>20:30:40</time>"
83                  + "<date>2002-03-17</date><projectMap/><bigDecimal>1234567890.12345</bigDecimal>"
84                  + "<bigInteger>1234567890</bigInteger><projectNames/><emails>"
85                  + "<email>jstrachan@apache.org</email><email>james_strachan@yahoo.co.uk</email>"
86                  + "</emails><timestamp>2002-03-17 20:30:40.0</timestamp><locations>"
87                  + "<location>London</location><location>Bath</location></locations>"
88                  + "<ID/><projectURLs/><nickName/><address><code/><country/>"
89                  + "<city/><street/></address><numbers><number>3</number><number>4</number>"
90                  + "<number>5</number></numbers></CustomerBean>";
91                  
92              xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
93          }
94          finally {
95              in.close();
96          }
97      }
98      
99      public void testWriteThenRead() throws Exception {
100         // test defaults
101         PersonBean bean = new PersonBean(21, "Samual Smith");
102         StringWriter stringWriter = new StringWriter();
103         BeanWriter beanWriter = new BeanWriter(stringWriter);
104         beanWriter.write(bean);
105         stringWriter.flush();
106         String xml = "<?xml version='1.0'?>" + stringWriter.toString();
107         
108         BeanReader reader = new BeanReader();
109         reader.registerBeanClass( PersonBean.class );
110         bean = (PersonBean) reader.parse(new StringReader(xml));
111         
112         assertEquals("Person age wrong", 21 , bean.getAge());
113         assertEquals("Person name wrong", "Samual Smith" , bean.getName());
114         
115         // test now with attributes for primitives
116         bean = new PersonBean(19, "John Smith");
117         stringWriter = new StringWriter();
118         beanWriter = new BeanWriter(stringWriter);
119         beanWriter.getXMLIntrospector().setAttributesForPrimitives(true);
120         beanWriter.write(bean);
121         stringWriter.flush();
122         xml = "<?xml version='1.0'?>" + stringWriter.toString();
123         
124         reader = new BeanReader();
125         reader.getXMLIntrospector().setAttributesForPrimitives(true);
126         reader.registerBeanClass( PersonBean.class );
127         bean = (PersonBean) reader.parse(new StringReader(xml));
128         
129         assertEquals("[Attribute] Person age wrong", 19 , bean.getAge());
130         assertEquals("[Attribute] Person name wrong", "John Smith" , bean.getName());
131     }
132 
133     public String writeBean(Object bean) throws Exception {
134         StringWriter out = new StringWriter();
135         out.write("<?xml version='1.0'?>");
136         BeanWriter writer = new BeanWriter(out);
137         writer.enablePrettyPrint();
138         writer.write( bean );
139         return out.getBuffer().toString();
140     }
141     
142     /*** @return the bean class to use as the root */
143     public Class getBeanClass() {
144         return CustomerBean.class;
145     }
146     
147     /*** 
148      * Asserts that the parsed CustomerBean looks fine
149      */
150     protected void testCustomer(Object bean) throws Exception {
151         assertTrue( "Is a CustomerBean", bean instanceof CustomerBean );
152         CustomerBean customer = (CustomerBean) bean;
153      
154         assertEquals( "name", "James", customer.getName() );
155         
156         String[] emails = customer.getEmails();
157         assertTrue( "contains some emails", emails != null );
158         assertEquals( "emails.length", 2, emails.length );
159         assertEquals( "emails[0]", "jstrachan@apache.org", emails[0] );
160         assertEquals( "emails[1]", "james_strachan@yahoo.co.uk", emails[1] );
161         
162         int[] numbers = customer.getNumbers();
163         assertTrue( "contains some numbers", numbers != null );
164         assertEquals( "numbers.length", 3, numbers.length );
165         assertEquals( "numbers[0]", 3, numbers[0] );
166         assertEquals( "numbers[1]", 4, numbers[1] );
167         assertEquals( "numbers[2]", 5, numbers[2] );
168         
169         List locations = customer.getLocations();
170         assertTrue( "contains some locations", locations != null );
171         assertEquals( "locations.size()", 2, locations.size() );
172         assertEquals( "locations[0]", "London", locations.get(0) );
173         assertEquals( "locations[1]", "Bath", locations.get(1) );
174         
175         assertEquals( ConvertUtils.convert("2002-03-17", Date.class), customer.getDate());
176         assertEquals( ConvertUtils.convert("20:30:40", Time.class), customer.getTime());
177         assertEquals( ConvertUtils.convert("2002-03-17 20:30:40.0", Timestamp.class), customer.getTimestamp());
178 
179         assertEquals( new BigDecimal("1234567890.12345"), customer.getBigDecimal() );
180         assertEquals( new BigInteger("1234567890"), customer.getBigInteger() );
181     }
182     
183     protected InputStream getXMLInput() throws IOException {
184         return new FileInputStream( getTestFile("src/test/org/apache/commons/betwixt/customer.xml") );
185     }
186  
187     /*** 
188      * This tests that you can read a bean which has an adder but not a property
189      */ 
190     public void testAdderButNoProperty() throws Exception {
191         /*
192         // 
193         // This is a test for an unfixed issue that might - or might not - be a bug
194         // a developer submitted a patch but this broke the other unit test
195         // a proper fix would require quite a lot of work including some refactoring
196         // of various interfaces
197         //
198         
199         // check bean's still working
200         AdderButNoPropertyBean bean = new AdderButNoPropertyBean();
201         bean.addString("one");
202         bean.addString("two");
203         bean.addString("three");
204         checkBean(bean);
205         
206         BeanReader reader = new BeanReader();
207         reader.registerBeanClass( AdderButNoPropertyBean.class );
208         
209         InputStream in =  
210             new FileInputStream( getTestFile("src/test/org/apache/commons/betwixt/adder-np.xml") );
211         try {
212         
213             checkBean((AdderButNoPropertyBean) reader.parse( in ));
214             
215         }
216         finally {
217             in.close();
218         }        
219         */
220     }
221     
222     private void checkBean(AdderButNoPropertyBean bean) throws Exception {
223         assertEquals("Bad addString call count", 3, bean.stringCallCount());
224     }
225     
226     private void checkBean(PersonListBean bean) throws Exception {
227         assertEquals("PersonList size", 4, bean.getPersonList().size());
228         assertEquals("PersonList value (1)", "Athos", ((PersonBean) bean.getPersonList().get(0)).getName());
229         assertEquals("PersonList value (2)", "Porthos", ((PersonBean) bean.getPersonList().get(1)).getName());
230         assertEquals("PersonList value (3)", "Aramis", ((PersonBean) bean.getPersonList().get(2)).getName());
231         assertEquals("PersonList value (4)", "D'Artagnan", ((PersonBean) bean.getPersonList().get(3)).getName());
232     }
233     
234     public void testPersonList() throws Exception {
235 
236         PersonListBean people = new PersonListBean();
237         people.addPerson(new PersonBean(22, "Athos"));
238         people.addPerson(new PersonBean(25, "Porthos"));
239         people.addPerson(new PersonBean(23, "Aramis"));
240         people.addPerson(new PersonBean(18, "D'Artagnan"));
241         
242         checkBean(people);
243 //
244 // Logging and debugging code for this method commented out
245 //
246 //        writeBean(people);
247 
248 //        SimpleLog log = new SimpleLog("[TestPersonList:XMLIntrospectorHelper]");
249 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
250 //        XMLIntrospectorHelper.setLog(log);
251         
252         
253 //        log = new SimpleLog("[TestPersonList:BeanCreateRule]");
254 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
255 //        BeanCreateRule.setLog(log);
256         
257 //        log = new SimpleLog("[TestPersonList:XMLIntrospector]");
258 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
259         
260         BeanReader reader = new BeanReader();
261 //        reader.getXMLIntrospector().setLog(log);
262               
263 //        log = new SimpleLog("[TestPersonList:BeanReader]");
264 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
265         
266 //        reader.setLog(log);
267         reader.registerBeanClass( PersonListBean.class );
268         
269         InputStream in =  
270             new FileInputStream( getTestFile("src/test/org/apache/commons/betwixt/person-list.xml") );
271         try {
272         
273             checkBean((PersonListBean) reader.parse( in ));
274             
275         }
276         finally {
277             in.close();
278         }   
279     }
280     
281     /*** Another test for reading wrapped collections */
282     public void testWrapElements() throws Exception {
283         ListOfNames listOfNames = new ListOfNames();
284         listOfNames.addName( new NameBean("Martin") );
285         
286         String xml = "<ListOfNames><names><name name='Martin'/></names></ListOfNames>";
287         
288         BeanReader reader = new BeanReader();
289         reader.getXMLIntrospector().setAttributesForPrimitives(true);
290         reader.getXMLIntrospector().setWrapCollectionsInElement(true);
291         
292         reader.registerBeanClass(ListOfNames.class);
293         ListOfNames newListOfNames = (ListOfNames) reader.parse(new StringReader(xml));
294         
295         assertEquals("Wrapped collection read fails", listOfNames, newListOfNames);
296     }
297     
298     public void testSetDigesterRules() throws Exception {
299         NameBean martinBean = new NameBean("Martin");
300         ListOfNames listOfNames = new ListOfNames();
301         listOfNames.addName( martinBean );
302         
303         String xml = "<ListOfNames><names><name name='Martin'/></names></ListOfNames>";
304         
305         BeanReader reader = new BeanReader();
306         reader.setRules( new ExtendedBaseRules() );
307         reader.getXMLIntrospector().setAttributesForPrimitives(true);
308         reader.getXMLIntrospector().setWrapCollectionsInElement(true);
309         
310         TestRule ruleOne = new TestRule();
311         TestRule ruleTwo = new TestRule();
312         
313         // add a test rule before the bean rules
314         reader.addRule("!*/ListOfNames/names/name", ruleOne);
315         reader.registerBeanClass(ListOfNames.class);
316         // add a test rule after the bean rules
317         reader.addRule("!*/ListOfNames/names/name", ruleTwo);
318         
319         ListOfNames newListOfNames = (ListOfNames) reader.parse(new StringReader(xml));
320         
321         reader.parse(new StringReader(xml));
322         
323         // test that the rules were called
324         assertEquals("Rule one called", true , ruleOne.isCalled());
325         assertEquals("Rule two called", true , ruleTwo.isCalled());
326         
327         // test that the top objects are correct
328         assertEquals("Rule one digester top object", listOfNames , ruleOne.getTop());
329         assertEquals("Rule two digester top object", martinBean , ruleTwo.getTop());
330     }
331     
332     public void testDateReadConversion() throws Exception {
333         Calendar calendar = Calendar.getInstance();
334         calendar.set(2003, 7, 2, 19, 30, 00);
335         java.util.Date date = calendar.getTime();
336         
337         String dateToString = date.toString();
338         
339         PartyBean bean = new PartyBean(
340                 "Wedding",
341                 date,
342                 1930,
343                 new AddressBean("Old White Lion Hotel", "Howarth", "Merry Old England", "BD22 8EP"));
344 
345         StringWriter out = new StringWriter();
346         out.write("<?xml version='1.0'?>");
347         
348         BeanWriter writer = new BeanWriter(out);
349         XMLIntrospector introspector = writer.getXMLIntrospector();
350         introspector.setElementNameMapper(new HyphenatedNameMapper());
351         introspector.setAttributesForPrimitives(false);
352         
353         writer.write("party", bean);
354 
355         String xml = "<?xml version='1.0'?><party>"
356             + "<venue><street>Old White Lion Hotel</street><city>Howarth</city>"
357             + "<code>BD22 8EP</code><country>Merry Old England</country></venue>"
358             + "<date-of-party>" + dateToString 
359             + "</date-of-party><from-hour>1930</from-hour>"
360             + "<excuse>Wedding</excuse>"
361             + "</party>";
362         
363         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
364         
365         BeanReader reader = new BeanReader();
366         reader.setXMLIntrospector(introspector);
367         reader.registerBeanClass("party", PartyBean.class);
368         PartyBean readBean = (PartyBean) reader.parse(new StringReader(xml)); 
369         
370         assertEquals("FromHours incorrect property value", readBean.getFromHour(), bean.getFromHour());
371         assertEquals("Excuse incorrect property value", readBean.getExcuse(), bean.getExcuse());
372         
373         // check address
374         AddressBean readAddress = readBean.getVenue();
375         AddressBean address = bean.getVenue();
376         assertEquals("address.street incorrect property value", readAddress.getStreet(), address.getStreet());
377         assertEquals("address.city incorrect property value", readAddress.getCity(), address.getCity());
378         assertEquals("address.code incorrect property value", readAddress.getCode(), address.getCode());
379         assertEquals("address.country incorrect property value", readAddress.getCountry(), address.getCountry());
380         
381         // check dates
382         assertEquals("Incorrect date property", date.toGMTString(), readBean.getDateOfParty().toGMTString());  
383     }
384  
385     public void testHyphenatedNameMapping() throws Exception {
386         Calendar calendar = Calendar.getInstance();
387         calendar.set(2003, 7, 2, 19, 30, 00);
388         java.util.Date date = calendar.getTime();
389         
390         String dateToString = date.toString();
391         
392         PartyBean bean = new PartyBean(
393                 "Wedding",
394                 date,
395                 1930,
396                 new AddressBean("Old White Lion Hotel", "Howarth", "Merry Old England", "BD22 8EP"));
397 
398         StringWriter out = new StringWriter();
399         out.write("<?xml version='1.0'?>");
400         
401         BeanWriter writer = new BeanWriter(out);
402         XMLIntrospector introspector = writer.getXMLIntrospector();
403         introspector.setElementNameMapper(new HyphenatedNameMapper());
404         introspector.setAttributesForPrimitives(false);
405         
406         writer.write(bean);
407         
408         String xml = "<?xml version='1.0'?><party-bean>"
409             + "<venue><street>Old White Lion Hotel</street><city>Howarth</city>"
410             + "<code>BD22 8EP</code><country>Merry Old England</country></venue>"
411             + "<date-of-party>" + dateToString 
412             + "</date-of-party><from-hour>1930</from-hour>"
413             + "<excuse>Wedding</excuse>"
414             + "</party-bean>";
415         
416         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
417         
418         BeanReader reader = new BeanReader();
419         reader.setXMLIntrospector(introspector);
420         reader.registerBeanClass(PartyBean.class);
421         PartyBean readBean = (PartyBean) reader.parse(new StringReader(xml)); 
422         
423         assertEquals("FromHours incorrect property value", readBean.getFromHour(), bean.getFromHour());
424         assertEquals("Excuse incorrect property value", readBean.getExcuse(), bean.getExcuse());
425         
426         // check address
427         AddressBean readAddress = readBean.getVenue();
428         AddressBean address = bean.getVenue();
429         assertEquals("address.street incorrect property value", readAddress.getStreet(), address.getStreet());
430         assertEquals("address.city incorrect property value", readAddress.getCity(), address.getCity());
431         assertEquals("address.code incorrect property value", readAddress.getCode(), address.getCode());
432         assertEquals("address.country incorrect property value", readAddress.getCountry(), address.getCountry());
433         
434         // check dates
435         assertEquals("Incorrect date property", date.toGMTString(), readBean.getDateOfParty().toGMTString());  
436         
437     }
438  
439     public void testCustomDateReadConversion() throws Exception {
440     
441         BindingConfiguration configuration = new BindingConfiguration(
442                                             new ConvertUtilsObjectStringConverter(),false);
443     
444         //SimpleLog log = new SimpleLog("testDateReadConversion:MethodUpdater");
445         //log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
446         //MethodUpdater.setLog(log);
447    
448         class ISOToStringConverter implements Converter {
449             final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
450             public Object convert(Class type, Object value) {
451                 if (value == null) {
452                     return null;
453                 }
454                 if (value instanceof java.util.Date) {
455                     return formatter.format((java.util.Date)value);
456                 }
457                 return value.toString();
458             }
459         }
460      
461         class ISODateConverter implements Converter {
462             final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
463             public Object convert(Class type, Object value) {
464 
465                 if (value == null) {
466                     return null;
467                 }
468                 
469                 if (value instanceof java.util.Date) {
470 
471                     return formatter.format((java.util.Date)value);
472                 }
473                 
474                 try {
475                     return formatter.parse(value.toString());
476                 } catch (ParseException ex) {
477                     throw new ConversionException(ex);
478                 }
479             }
480         }
481         
482         ISODateConverter converter = new ISODateConverter();
483         ConvertUtils.register(converter, java.util.Date.class);
484         ISOToStringConverter tsConverter = new ISOToStringConverter();
485         ConvertUtils.register(tsConverter, String.class);
486         
487         Converter dateConverter = ConvertUtils.lookup(java.util.Date.class);
488         assertEquals("Date converter successfully registered", dateConverter, converter);
489         Converter stringConverter = ConvertUtils.lookup(String.class);
490         assertEquals("Date converter successfully registered", tsConverter, stringConverter);
491         
492         java.util.Date conversionResult = (java.util.Date)
493                                 ConvertUtils.convert("20030101", java.util.Date.class);
494         
495         Calendar calendar = Calendar.getInstance();
496         calendar.setTime(conversionResult);
497         int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
498         assertEquals("Correct conversion result", dayOfYear, 1);
499         
500         calendar.set(2003, 7, 2);
501         java.util.Date date = calendar.getTime();
502         
503         PartyBean bean = new PartyBean(
504                 "Wedding",
505                 date,
506                 1900,
507                 new AddressBean("Old White Lion Hotel", "Howarth", "Merry Old England", "BD22 8EP"));
508 
509         StringWriter out = new StringWriter();
510         out.write("<?xml version='1.0'?>");
511         
512         BeanWriter writer = new BeanWriter(out);
513         writer.setBindingConfiguration(configuration);
514         XMLIntrospector introspector = writer.getXMLIntrospector();
515         introspector.setElementNameMapper(new HyphenatedNameMapper());
516         introspector.setAttributesForPrimitives(false);
517         
518         writer.write("party", bean);
519 
520         String xml = "<?xml version='1.0'?><party>"
521             + "<venue><street>Old White Lion Hotel</street><city>Howarth</city>"
522             + "<code>BD22 8EP</code><country>Merry Old England</country></venue>"
523             + "<date-of-party>20030802</date-of-party><from-hour>1900</from-hour>"
524             + "<excuse>Wedding</excuse>"
525             + "</party>";
526         
527         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
528         
529         BeanReader reader = new BeanReader();
530         reader.setBindingConfiguration(configuration);
531         reader.setXMLIntrospector(introspector);
532         reader.registerBeanClass("party", PartyBean.class);
533         PartyBean readBean = (PartyBean) reader.parse(new StringReader(xml)); 
534         
535         assertEquals("FromHours incorrect property value", readBean.getFromHour(), bean.getFromHour());
536         assertEquals("Excuse incorrect property value", readBean.getExcuse(), bean.getExcuse());
537         
538         // check address
539         AddressBean readAddress = readBean.getVenue();
540         AddressBean address = bean.getVenue();
541         assertEquals("address.street incorrect property value", readAddress.getStreet(), address.getStreet());
542         assertEquals("address.city incorrect property value", readAddress.getCity(), address.getCity());
543         assertEquals("address.code incorrect property value", readAddress.getCode(), address.getCode());
544         assertEquals("address.country incorrect property value", readAddress.getCountry(), address.getCountry());
545         
546         // check dates
547         calendar.setTime(bean.getDateOfParty());
548         calendar.set(Calendar.HOUR_OF_DAY, 0);
549         dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
550         int year = calendar.get(Calendar.YEAR);
551         calendar.setTime(readBean.getDateOfParty());
552         calendar.set(Calendar.HOUR_OF_DAY, 0);
553         int readDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);    
554         int readYear = calendar.get(Calendar.YEAR); 
555         assertEquals("date incorrect property value (year)", year, readYear); 
556         assertEquals("date incorrect property value (day)", dayOfYear, readDayOfYear);   
557         
558         ConvertUtils.deregister();
559     }
560 
561     
562     public void testReadMap() throws Exception {
563         // we might as well start by writing out 
564         MapBean bean = new MapBean("drinkers");
565         bean.addAddress(
566                 "Russell McManus", 
567                 new AddressBean("6, Westgate","Shipley", "United Kingdom", "BD17 5EJ"));
568         bean.addAddress(
569                 "Alex Compbell", 
570                 new AddressBean("5, Kirkgate","Shipley", "United Kingdom", "BD18 3QW"));
571         bean.addAddress(
572                 "Sid Gardner", 
573                 new AddressBean("Old House At Home, Otley Road","Shipley", "United Kingdom", "BD18 2BJ"));
574                 
575         StringWriter out = new StringWriter();
576         out.write("<?xml version='1.0'?>");
577         BeanWriter writer = new BeanWriter(out);
578         writer.setWriteIDs(false);
579         writer.write("address-book", bean);
580         
581         String xml = "<?xml version='1.0'?><address-book><title>drinkers</title>"
582             + "<addresses>"
583             + "<entry><key>Alex Compbell</key><value><country>United Kingdom</country>"
584             + "<code>BD18 3QW</code><city>Shipley</city><street>5, Kirkgate</street></value></entry>"
585             + "<entry><key>Russell McManus</key><value><country>United Kingdom</country><code>BD17 5EJ</code>"
586             + "<city>Shipley</city><street>6, Westgate</street></value></entry>"
587             + "<entry><key>Sid Gardner</key><value><country>United Kingdom</country>"
588             + "<code>BD18 2BJ</code><city>Shipley</city><street>Old House At Home, Otley Road</street>"
589             + "</value></entry>"
590             + "</addresses></address-book>";
591         
592         xmlAssertIsomorphic(parseString(out.toString()), parseString(xml), true);
593         
594 //        SimpleLog log = new SimpleLog("[testReadMap:BeanRuleSet]");
595 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
596 //        BeanRuleSet.setLog(log);
597 //        log = new SimpleLog("[testReadMap:XMLIntrospectorHelper]");
598 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
599 //        XMLIntrospectorHelper.setLog(log);
600 //        log = new SimpleLog("[testReadMap:MapEntryAdder]");
601 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
602 //        MapEntryAdder.setLog(log);
603 
604         BeanReader reader = new BeanReader();
605 
606 //        log = new SimpleLog("[testReadMap:BeanReader]");
607 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
608 //        reader.setLog(log);
609 //        log = new SimpleLog("[testReadMap:XMLIntrospector]");
610 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
611 //        reader.getXMLIntrospector().setLog(log);
612 
613         reader.setMatchIDs(false);
614         reader.registerBeanClass("address-book", MapBean.class);
615         bean = (MapBean) reader.parse(new StringReader(xml));
616         
617         assertEquals("Title property is incorrect", "drinkers", bean.getTitle());
618         assertEquals("Map entries", 3, bean.getAddresses().size());
619         
620         AddressBean address = (AddressBean) bean.getAddresses().get("Russell McManus");
621         assertNotNull("Missing entry for 'Russell McManus'", address);
622         assertEquals("Bad address (1)", "6, Westgate", address.getStreet());
623         assertEquals("Bad address (2)", "Shipley", address.getCity());
624         assertEquals("Bad address (3)",  "United Kingdom", address.getCountry());
625         assertEquals("Bad address (4)", "BD17 5EJ", address.getCode());
626                     
627         address = (AddressBean) bean.getAddresses().get("Alex Compbell");
628         assertNotNull("Missing entry for 'Alex Compbell'", address);
629         assertEquals("Bad address (5)", "5, Kirkgate", address.getStreet());
630         assertEquals("Bad address (6)", "Shipley", address.getCity());
631         assertEquals("Bad address (7)",  "United Kingdom", address.getCountry());
632         assertEquals("Bad address (8)", "BD18 3QW", address.getCode());
633          
634         address = (AddressBean) bean.getAddresses().get("Sid Gardner");
635         assertNotNull("Missing entry for 'Sid Gardner'", address);
636         assertEquals("Bad address (9)", "Old House At Home, Otley Road", address.getStreet());
637         assertEquals("Bad address (10)", "Shipley", address.getCity());
638         assertEquals("Bad address (11)",  "United Kingdom", address.getCountry());
639         assertEquals("Bad address (12)", "BD18 2BJ", address.getCode());
640     }
641     
642     public void testIndirectReference() throws Exception
643     {	
644         Tweedledum dum = new Tweedledum();
645         Tweedledee dee = new Tweedledee(dum);
646         StringWriter out = new StringWriter();
647         out.write("<?xml version='1.0'?>");
648         BeanWriter writer = new BeanWriter(out);
649         writer.setWriteIDs(false);
650         writer.write(dee);
651         String xml =  "<?xml version='1.0'?><Tweedledee><name>Tweedledee</name>"
652                     + "<brother><name>Tweedledum</name></brother></Tweedledee>";
653         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
654 
655         BeanReader reader = new BeanReader();
656         
657         reader.setMatchIDs(false);
658         reader.registerBeanClass(Tweedledee.class);
659         Tweedledee bean = (Tweedledee) reader.parse(new StringReader(xml));
660         assertNotNull(bean.getBrother());
661     }
662     
663     public void _testDoubleLinkedCollectionRead() throws Exception
664     {
665         String xml =  "<?xml version='1.0'?><DOUBLE_LINKED_PARENT_BEAN>"
666                     + "<NAME>Cronus</NAME>"
667                     + "<CHILDREN>"
668                     + "<CHILD><NAME>Hades</NAME></CHILD>"
669                     + "<CHILD><NAME>Hera</NAME></CHILD>"
670                     + "<CHILD><NAME>Hestia</NAME></CHILD>"
671                     + "<CHILD><NAME>Demeter</NAME></CHILD>"
672                     + "<CHILD><NAME>Poseidon</NAME></CHILD>"
673                     + "<CHILD><NAME>Zeus</NAME></CHILD>"
674                     + "</CHILDREN></DOUBLE_LINKED_PARENT_BEAN>";
675                     
676         BeanReader reader = new BeanReader();
677         reader.getXMLIntrospector().setElementNameMapper(new HyphenatedNameMapper(true, "_"));
678         reader.registerBeanClass(DoubleLinkedParentBean.class);
679         DoubleLinkedParentBean bean = (DoubleLinkedParentBean) reader.parse(new StringReader(xml));
680         
681         assertNotNull("Bean read", bean);
682         assertEquals("Cronus", "Parent name", bean.getName());
683         assertEquals("Number of children", 6, bean.getSize());
684         
685         ArrayList list = new ArrayList();
686         CollectionUtils.addAll(list, bean.getChildren());
687         
688         DoubleLinkedChildBean childZero = (DoubleLinkedChildBean) list.get(0);
689         DoubleLinkedChildBean childOne = (DoubleLinkedChildBean) list.get(1);
690         DoubleLinkedChildBean childTwo = (DoubleLinkedChildBean) list.get(2);
691         DoubleLinkedChildBean childThree = (DoubleLinkedChildBean) list.get(3);
692         DoubleLinkedChildBean childFour = (DoubleLinkedChildBean) list.get(4);
693         DoubleLinkedChildBean childFive = (DoubleLinkedChildBean) list.get(5);
694  
695         assertEquals("Child name zero", "Hades", childZero.getName());
696         assertEquals("Child name one", "Hera", childZero.getName());
697         assertEquals("Child name two", "Hestia", childZero.getName());
698         assertEquals("Child name three", "Demeter", childZero.getName());
699         assertEquals("Child name four", "Poseidon", childZero.getName());
700         assertEquals("Child name five", "Zeus", childZero.getName());
701         
702     }
703     
704     /*** 
705       * This is a member class since all classes starting with test 
706       * will be run as test cases.
707       */
708     private class TestRule extends Rule {
709         
710         private String name;
711         private boolean called = false;
712         private Object top;
713         
714         public Object getTop() {
715             return top;
716         }
717         
718         public String getName() {
719             return name;
720         }
721         
722         public void setName(String name) {
723             this.name = name;
724         }	
725         
726         public boolean isCalled() {
727             return called;
728         }
729         
730         public void begin(Attributes attributes) {
731             top = getDigester().peek();
732             called = true;
733         }
734     }
735 }
736