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