/Prototipo/Servlet/lib/xstream-distribution-1.4.1-bin/xstream-1.4.1/docs/converter-tutorial.html

http://prototipomemoria.googlecode.com/ · HTML · 693 lines · 558 code · 123 blank · 12 comment · 0 complexity · fc036998685304a6130ad91049187bb6 MD5 · raw file

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <!--
  4. Copyright (C) 2005, 2006 Joe Walnes.
  5. Copyright (C) 2006, 2007, 2008 XStream committers.
  6. All rights reserved.
  7. The software in this package is published under the terms of the BSD
  8. style license a copy of which has been included with this distribution in
  9. the LICENSE.txt file.
  10. Created on 29. January 2005 by Joe Walnes
  11. -->
  12. <head>
  13. <title>XStream - Converter Tutorial</title>
  14. <link rel="stylesheet" type="text/css" href="style.css"/>
  15. <!-- Google analytics -->
  16. <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
  17. </script>
  18. <script type="text/javascript">
  19. _uacct = "UA-110973-2";
  20. urchinTracker();
  21. </script>
  22. </head>
  23. <body>
  24. <div id="banner">
  25. <a href="index.html"><img id="logo" src="logo.gif" alt="XStream"/></a>
  26. </div>
  27. <div id="center" class="Content2Column"> <!-- Content3Column for index -->
  28. <div id="content">
  29. <h1 class="FirstChild">Converter Tutorial</h1>
  30. <h1 id="SimpleConverter">Simple Converter</h1>
  31. <h2>Setting up a simple example</h2>
  32. <p>This is the most basic converter... let's start with a simple Person:</p>
  33. <div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  34. public class Person {
  35. private String name;
  36. public String getName() {
  37. return name;
  38. }
  39. public void setName(String name) {
  40. this.name = name;
  41. }
  42. }</pre></div><p>So let's create a person and convert it to
  43. XML...</p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  44. import com.thoughtworks.xstream.XStream;
  45. import com.thoughtworks.xstream.io.xml.DomDriver;
  46. public class PersonTest {
  47. public static void main(String[] args) {
  48. Person person = new Person();
  49. person.setName(&quot;Guilherme&quot;);
  50. XStream xStream = new XStream(new DomDriver());
  51. System.out.println(xStream.toXML(person));
  52. }
  53. }</pre></div><p>This results in a really ugly XML code which contains the full
  54. class name (including
  55. package)...</p><div class="Source Java"><pre>&lt;com.thoughtworks.xstream.examples.Person&gt;
  56. &lt;name&gt;Guilherme&lt;/name&gt;
  57. &lt;/com.thoughtworks.xstream.examples.Person&gt;</pre></div><p>So we make use
  58. of an 'alias' to change this full class name to something more 'human', for
  59. example
  60. 'person'.</p><div class="Source Java"><pre>XStream xStream = new XStream(new DomDriver());
  61. xStream.alias(&quot;person&quot;, Person.class);
  62. System.out.println(xStream.toXML(person));</pre></div><p>And the outcome is
  63. much easier to read (and
  64. smaller):</p><div class="Source Java"><pre>&lt;person&gt;
  65. &lt;name&gt;Guilherme&lt;/name&gt;
  66. &lt;/person&gt;</pre></div><p>Now that we have configured a simple class to
  67. play with, let's see what XStream converters can do for us...</p>
  68. <h2 id="CreatingPersonConverter">Creating a PersonConverter</h2>
  69. <p>Let's create a simple converter capable
  70. of:</p><ol style="list-style-type: decimal">
  71. <li>telling its capable of converting Person's</li>
  72. <li>translating a Person instance in XML</li>
  73. <li>translate XML into a new Person</li>
  74. </ol><p>We begin creating the PersonConverter class and implementing the
  75. Converter
  76. interface:</p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  77. import com.thoughtworks.xstream.converters.Converter;
  78. import com.thoughtworks.xstream.converters.MarshallingContext;
  79. import com.thoughtworks.xstream.converters.UnmarshallingContext;
  80. import com.thoughtworks.xstream.io.HierarchicalStreamReader;
  81. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  82. public class PersonConverter implements Converter {
  83. public boolean canConvert(Class clazz) {
  84. return false;
  85. }
  86. public void marshal(Object value, HierarchicalStreamWriter writer,
  87. MarshallingContext context) {
  88. }
  89. public Object unmarshal(HierarchicalStreamReader reader,
  90. UnmarshallingContext context) {
  91. return null;
  92. }
  93. }</pre></div><p>Now we tell whoever calls us that we can handle only Person's
  94. (and <b>nothing</b> else, including those classes which extends
  95. Person).</p><div class="Source Java"><pre>public boolean canConvert(Class clazz) {
  96. return clazz.equals(Person.class);
  97. }</pre></div><p>The second step is usually quite clean, unless you are dealing
  98. with generic converters.</p><p>The marshal method is responsible for
  99. translating an object to XML. It receives three
  100. arguments:</p><ol style="list-style-type: decimal">
  101. <li>the object we are trying to convert</li>
  102. <li>the writer were we should output the data</li>
  103. <li>the current marshalling context</li>
  104. </ol><p>We start casting the object to
  105. person:</p><div class="Source Java"><pre>Person person = (Person) value;</pre></div><p>Now
  106. we can output the data... let's start creating a node called <i>fullname</i>
  107. and adding the person's name to
  108. it:</p><div class="Source Java"><pre>writer.startNode(&quot;fullname&quot;);
  109. writer.setValue(person.getName());
  110. writer.endNode();</pre></div><p>Quite simple
  111. huh?</p><div class="Source Java"><pre>public void marshal(Object value, HierarchicalStreamWriter writer,
  112. MarshallingContext context) {
  113. Person person = (Person) value;
  114. writer.startNode(&quot;fullname&quot;);
  115. writer.setValue(person.getName());
  116. writer.endNode();
  117. }</pre></div><p>We could have called start/end node as many times as we would
  118. like (but remember to close everything you open)... and conversion usually
  119. takes place when calling the <i>setValue</i> method.</p><p>And now let's go to
  120. the unmarshal. We use the <i>moveDown</i> and <i>moveUp</i> methods to move
  121. in the tree hierarchy, so we can simply <i>moveDown</i>, read the value and
  122. <i>moveUp</i>.</p><div class="Source Java"><pre> Person person = new Person();
  123. reader.moveDown();
  124. person.setName(reader.getValue());
  125. reader.moveUp();</pre></div><p>Which gives us the following
  126. converter:</p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  127. import com.thoughtworks.xstream.converters.Converter;
  128. import com.thoughtworks.xstream.converters.MarshallingContext;
  129. import com.thoughtworks.xstream.converters.UnmarshallingContext;
  130. import com.thoughtworks.xstream.io.HierarchicalStreamReader;
  131. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  132. public class PersonConverter implements Converter {
  133. public boolean canConvert(Class clazz) {
  134. return clazz.equals(Person.class);
  135. }
  136. public void marshal(Object value, HierarchicalStreamWriter writer,
  137. MarshallingContext context) {
  138. Person person = (Person) value;
  139. writer.startNode(&quot;fullname&quot;);
  140. writer.setValue(person.getName());
  141. writer.endNode();
  142. }
  143. public Object unmarshal(HierarchicalStreamReader reader,
  144. UnmarshallingContext context) {
  145. Person person = new Person();
  146. reader.moveDown();
  147. person.setName(reader.getValue());
  148. reader.moveUp();
  149. return person;
  150. }
  151. }</pre></div><p>Now let's register our converter and see how our application
  152. <i>main</i> method looks
  153. like:</p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  154. import com.thoughtworks.xstream.XStream;
  155. import com.thoughtworks.xstream.io.xml.DomDriver;
  156. public class PersonTest {
  157. public static void main(String[] args) {
  158. Person person = new Person();
  159. person.setName(&quot;Guilherme&quot;);
  160. XStream xStream = new XStream(new DomDriver());
  161. xStream.registerConverter(new PersonConverter());
  162. xStream.alias(&quot;person&quot;, Person.class);
  163. System.out.println(xStream.toXML(person));
  164. }
  165. }</pre></div><p>Did you notice how we registered our converter? It's a simple
  166. call to
  167. <i>registerConverter</i>:</p><div class="Source Java"><pre>xStream.registerConverter(new PersonConverter());</pre></div><p>The
  168. final result
  169. is:</p><div class="Source Java"><pre>&lt;person&gt;
  170. &lt;fullname&gt;Guilherme&lt;/fullname&gt;
  171. &lt;/person&gt;</pre></div><p>So you might say... that only changed my tree, I
  172. want to convert data!</p><p>Try using an attribute called <i>fullname</i> in
  173. the <i>person</i> tag instead of creating a new child node.</p>
  174. <h2 id="SingleValueConverter">An alternative for types with String representation</h2>
  175. <p>Let's enhance the Person with a String representation, that contains all necessary
  176. text to recreate the instance:</p>
  177. <div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  178. public class Person {
  179. private String name;
  180. public String getName() {
  181. return name;
  182. }
  183. public void setName(String name) {
  184. this.name = name;
  185. }
  186. public String toString() {
  187. return getName();
  188. }
  189. }</pre></div><p>In this case we can simplify our Converter to</p>
  190. <div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  191. import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;
  192. public class PersonConverter extends AbstractSingleValueConverter {
  193. public boolean canConvert(Class clazz) {
  194. return clazz.equals(Person.class);
  195. }
  196. public Object fromString(String str) {
  197. Person person = new Person();
  198. person.setName(string);
  199. return person;
  200. }
  201. }</pre></div><p>But even nicer, our XML is also simplified (using the alias for the
  202. Person class). Since the String representation is complete, a nested element is not
  203. necessary anymore:</p>
  204. <div class="Source Java"><pre>&lt;person&gt;Guilherme&lt;/person&gt;</pre></div>
  205. <h1 id="CustomConverter">Date Converter</h1>
  206. <p>Now that we know how the <i>Converter</i> interface works, let's create a
  207. simple calendar converter which uses the locale to convert the
  208. information.</p><p>Our converter will receive the Locale in its constructor
  209. and we will keep a reference to it in a member
  210. variable:</p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  211. import java.util.Locale;
  212. import com.thoughtworks.xstream.converters.Converter;
  213. import com.thoughtworks.xstream.converters.MarshallingContext;
  214. import com.thoughtworks.xstream.converters.UnmarshallingContext;
  215. import com.thoughtworks.xstream.io.HierarchicalStreamReader;
  216. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  217. public class DateConverter implements Converter {
  218. private Locale locale;
  219. public DateConverter(Locale locale) {
  220. super();
  221. this.locale = locale;
  222. }
  223. public boolean canConvert(Class clazz) {
  224. return false;
  225. }
  226. public void marshal(Object value, HierarchicalStreamWriter writer,
  227. MarshallingContext context) {
  228. }
  229. public Object unmarshal(HierarchicalStreamReader reader,
  230. UnmarshallingContext context) {
  231. return null;
  232. }
  233. }</pre></div><p>Now let's convert anything which extends <i>Calendar</i>:
  234. means if instances of class <i>clazz</i> can be assigned to the
  235. <i>Calendar</i> class, they extends the abstract class
  236. <i>Calendar</i>:</p><div class="Source Java"><pre>public boolean canConvert(Class clazz) {
  237. return Calendar.class.isAssignableFrom(clazz);
  238. }</pre></div><p>Let's go for converting a <i>Calendar</i> in a localized
  239. string... we first cast the object to <i>Calendar</i>, extract its <i>Date</i>
  240. and then use a <i>DateFormat</i> factory method to get a date converter to our
  241. localized
  242. string.</p><div class="Source Java"><pre>public void marshal(Object value, HierarchicalStreamWriter writer,
  243. MarshallingContext context) {
  244. Calendar calendar = (Calendar) value;
  245. // grabs the date
  246. Date date = calendar.getTime();
  247. // grabs the formatter
  248. DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
  249. this.locale);
  250. // formats and sets the value
  251. writer.setValue(formatter.format(date));
  252. }</pre></div><p>And the other way around... in order to unmarshall, we create
  253. a <i>GregorianCalendar</i>, retrieves the localized <i>DateFormat</i>
  254. instance, parses the string into a <i>Date</i> and puts this date in the
  255. original
  256. <i>GregorianCalendar</i>:</p><div class="Source Java"><pre>public Object unmarshal(HierarchicalStreamReader reader,
  257. UnmarshallingContext context) {
  258. // creates the calendar
  259. GregorianCalendar calendar = new GregorianCalendar();
  260. // grabs the converter
  261. DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
  262. this.locale);
  263. // parses the string and sets the time
  264. try {
  265. calendar.setTime(formatter.parse(reader.getValue()));
  266. } catch (ParseException e) {
  267. throw new ConversionException(e.getMessage(), e);
  268. }
  269. // returns the new object
  270. return calendar;
  271. }</pre></div><p>Note 1: remember that some <i>DateFormat</i> implementations
  272. are not thread-safe, therefore don't put your formatter as a member of your
  273. converter.</p><p>Note 2: this implementation <b>will</b> convert other types
  274. of Calendar's to GregorianCalendar after save/load. If this is not what you
  275. want, change your <i>canConvert</i> method to return <i>true</i> only if
  276. <i>class</i> equals <i>GregorianCalendar</i>.</p><p>So we get the following
  277. converter:</p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  278. import java.text.DateFormat;
  279. import java.text.ParseException;
  280. import java.util.Calendar;
  281. import java.util.Date;
  282. import java.util.GregorianCalendar;
  283. import java.util.Locale;
  284. import com.thoughtworks.xstream.converters.ConversionException;
  285. import com.thoughtworks.xstream.converters.Converter;
  286. import com.thoughtworks.xstream.converters.MarshallingContext;
  287. import com.thoughtworks.xstream.converters.UnmarshallingContext;
  288. import com.thoughtworks.xstream.io.HierarchicalStreamReader;
  289. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  290. public class DateConverter implements Converter {
  291. private Locale locale;
  292. public DateConverter(Locale locale) {
  293. super();
  294. this.locale = locale;
  295. }
  296. public boolean canConvert(Class clazz) {
  297. return Calendar.class.isAssignableFrom(clazz);
  298. }
  299. public void marshal(Object value, HierarchicalStreamWriter writer,
  300. MarshallingContext context) {
  301. Calendar calendar = (Calendar) value;
  302. Date date = calendar.getTime();
  303. DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
  304. this.locale);
  305. writer.setValue(formatter.format(date));
  306. }
  307. public Object unmarshal(HierarchicalStreamReader reader,
  308. UnmarshallingContext context) {
  309. GregorianCalendar calendar = new GregorianCalendar();
  310. DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
  311. this.locale);
  312. try {
  313. calendar.setTime(formatter.parse(reader.getValue()));
  314. } catch (ParseException e) {
  315. throw new ConversionException(e.getMessage(), e);
  316. }
  317. return calendar;
  318. }
  319. }</pre></div><p>And let's try it out. We create a <i>DateTest</i> class with a
  320. <i>main</i> method:</p><ol style="list-style-type: decimal">
  321. <li>creates a calendar (current date)</li>
  322. <li>creates the XStream object</li>
  323. <li>registers the converter with a Brazilian Portuguese locale</li>
  324. <li>translates the object in XML</li>
  325. </ol>
  326. <p>Well, we already know how to do all those steps... so let's go:</p>
  327. <div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  328. import java.util.Calendar;
  329. import java.util.GregorianCalendar;
  330. import java.util.Locale;
  331. import com.thoughtworks.xstream.XStream;
  332. import com.thoughtworks.xstream.io.xml.DomDriver;
  333. public class DateTest {
  334. public static void main(String[] args) {
  335. // grabs the current date from the virtual machine
  336. Calendar calendar = new GregorianCalendar();
  337. // creates the xstream
  338. XStream xStream = new XStream(new DomDriver());
  339. // brazilian portuguese locale
  340. xStream.registerConverter(new DateConverter(new Locale(&quot;pt&quot;, &quot;br&quot;)));
  341. // prints the result
  342. System.out.println(xStream.toXML(calendar));
  343. }
  344. }</pre></div><p>The result? Well... it depends, but it will be something
  345. like:</p><div class="Source Java"><pre>&lt;gregorian-calendar&gt;Sexta-feira, 10 de Fevereiro de 2006&lt;/gregorian-calendar&gt;</pre></div><p>Note:
  346. we did not put any alias as <i>gregorian-calendar</i> is the default alias for
  347. <i>GregorianCalendar</i>.</p><p>And now let's try to unmarshal the result
  348. shown
  349. above:</p><div class="Source Java"><pre>// loads the calendar from the string
  350. Calendar loaded = (Calendar) xStream
  351. .fromXML(&quot;&lt;gregorian-calendar&gt;Sexta-feira, 10 de Fevereiro de 2006&lt;/gregorian-calendar&gt;&quot;);</pre></div><p>And
  352. print it using the system locale, short date
  353. format:</p><div class="Source Java"><pre>// prints using the system defined locale
  354. System.out.println(DateFormat.getDateInstance(DateFormat.SHORT).format(
  355. loaded.getTime()));</pre></div><p>The result might be
  356. something like (if your system locale is American
  357. English):</p><div class="Source Java"><pre>2/10/06</pre></div>
  358. <h1 id="ComplexConverter">Complex Converter</h1>
  359. <h2>Setting up another example</h2>
  360. <p>We already defined some classes, so let them glue together:</p>
  361. <div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  362. public class Birthday {
  363. private Person person;
  364. private Calendar date;
  365. private char gender;
  366. public Person getPerson() {
  367. return person;
  368. }
  369. public void setPerson(Person person) {
  370. this.person = person;
  371. }
  372. public Calendar getDate() {
  373. return date;
  374. }
  375. public void setDate(Calendar date) {
  376. this.date = date;
  377. }
  378. public char getGender() {
  379. return gender;
  380. }
  381. public void setGenderMale() {
  382. this.gender = 'm';
  383. }
  384. public void setGenderFemale() {
  385. this.gender = 'f';
  386. }
  387. }</pre></div><p>While XStream is capable of converting this class without any problem, we write our own custom converter
  388. just for demonstration. This time we want to reuse our already written converters for the Person and the Calendar and add an
  389. own attribute for the gender. The <code>canConvert</code> method is plain simple. We convert no derived classes this time,
  390. since they might have additional fields. But we reuse the converters registered in XStream for our member fields and handle
  391. <code>null</code> values:
  392. </p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  393. import java.util.Calendar;
  394. import com.thoughtworks.xstream.converters.ConversionException;
  395. import com.thoughtworks.xstream.converters.Converter;
  396. import com.thoughtworks.xstream.converters.MarshallingContext;
  397. import com.thoughtworks.xstream.converters.UnmarshallingContext;
  398. import com.thoughtworks.xstream.io.HierarchicalStreamReader;
  399. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  400. public class BirthdayConverter implements Converter {
  401. public boolean canConvert(Class clazz) {
  402. return Birthday.class == clazz;
  403. }
  404. public void marshal(Object value, HierarchicalStreamWriter writer,
  405. MarshallingContext context) {
  406. Birthday birthday = (Birthday)value;
  407. if (birthday.getGender() != '\0') {
  408. writer.addAttribute("gender", Character.toString(birthday.getGender()));
  409. }
  410. if (birthday.getPerson() != null) {
  411. writer.startNode("person");
  412. context.convertAnother(birthday.getPerson());
  413. writer.endNode();
  414. }
  415. if (birthday.getDate() != null) {
  416. writer.startNode("birth");
  417. context.convertAnother(birthday.getDate());
  418. writer.endNode();
  419. }
  420. }
  421. public Object unmarshal(HierarchicalStreamReader reader,
  422. UnmarshallingContext context) {
  423. Birthday birthday = new Birthday();
  424. String gender = reader.getAttribute("gender");
  425. if (gender != null) {
  426. if (gender.length() &gt; 0) {
  427. if (gender.char(0) == 'f') {
  428. birthday.setGenderFemale();
  429. } else if (gender.char(0) == 'm') {
  430. birthday.setFemale();
  431. } else {
  432. throw new ConversionException("Invalid gender value: " + gender);
  433. }
  434. } else {
  435. throw new ConversionException("Empty string is invalid gender value");
  436. }
  437. }
  438. while (reader.hasMoreChildren()) {
  439. reader.moveDown();
  440. if ("person".equals(reader.getNodeName())) {
  441. Person person = (Person)context.convertAnother(birthday, Person.class);
  442. birthday.setPerson(person);
  443. } else if ("birth".equals(reader.getNodeName())) {
  444. Calendar date = (Calendar)context.convertAnother(birthday, Calendar.class);
  445. birthday.setDate(date);
  446. }
  447. reader.moveUp();
  448. }
  449. return birthday;
  450. }
  451. }</pre></div><p>The unmarshal method ensures the valid value for the gender by throwing a
  452. ConversionException for invalid entries.</p>
  453. <p class=highlight>Note, that attributes will always have to be written and read first. You work on a stream and
  454. accessing the value of a tag or its members will close the surrounding tag (that is still active when the method is
  455. called).</p>
  456. <p>If the implementation of <code>Birthday</code> ensures, that none of its fields
  457. could hold a <code>null</code> value and gender contains a valid value, then we could drop the
  458. <code>null</code> condition in the <code>marshal</code> method and in <code>unmarshal</code>
  459. we could omit the loop as well as the comparison of the tag names:</p><div class="Source Java"><pre>package com.thoughtworks.xstream.examples;
  460. import java.util.Calendar;
  461. import com.thoughtworks.xstream.converters.Converter;
  462. import com.thoughtworks.xstream.converters.MarshallingContext;
  463. import com.thoughtworks.xstream.converters.UnmarshallingContext;
  464. import com.thoughtworks.xstream.io.HierarchicalStreamReader;
  465. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  466. public class BirthdayConverter implements Converter {
  467. public boolean canConvert(Class clazz) {
  468. return Birthday.class == clazz;
  469. }
  470. public void marshal(Object value, HierarchicalStreamWriter writer,
  471. MarshallingContext context) {
  472. writer.addAttribute("gender", Character.toString(birthday.getGender()));
  473. Birthday birthday = (Birthday)value;
  474. writer.startNode("person");
  475. context.convertAnother(birthday.getPerson());
  476. writer.endNode();
  477. writer.startNode("birth");
  478. context.convertAnother(birthday.getDate());
  479. writer.endNode();
  480. }
  481. public Object unmarshal(HierarchicalStreamReader reader,
  482. UnmarshallingContext context) {
  483. Birthday birthday = new Birthday();
  484. if (reader.getAttribute("gender").charAt(0) == 'm') {
  485. birthday.setGenderMale();
  486. } else {
  487. birthday.setGenderFemale();
  488. }
  489. reader.moveDown();
  490. Person person = (Person)context.convertAnother(birthday, Person.class);
  491. birthday.setPerson(person);
  492. reader.moveUp();
  493. reader.moveDown();
  494. Calendar date = (Calendar)context.convertAnother(birthday, Calendar.class);
  495. birthday.setDate(date);
  496. reader.moveUp();
  497. return birthday;
  498. }
  499. }</pre></div>
  500. <br/>
  501. </div>
  502. </div>
  503. <div class="SidePanel" id="left">
  504. <div class="MenuGroup">
  505. <h1>Software</h1>
  506. <ul>
  507. <li><a href="index.html">About XStream</a></li>
  508. <li><a href="news.html">News</a></li>
  509. <li><a href="changes.html">Change History</a></li>
  510. <li><a href="versioning.html">About Versioning</a></li>
  511. </ul>
  512. </div>
  513. <div class="MenuGroup">
  514. <h1>Evaluating XStream</h1>
  515. <ul>
  516. <li><a href="tutorial.html">Two Minute Tutorial</a></li>
  517. <li><a href="graphs.html">Object references</a></li>
  518. <li><a href="manual-tweaking-output.html">Tweaking the Output</a></li>
  519. <li><a href="license.html">License</a></li>
  520. <li><a href="download.html">Download</a></li>
  521. <li><a href="references.html">References</a></li>
  522. <li><a href="parser-benchmarks.html">Parser Benchmarks</a></li>
  523. <li><a href="http://www.ohloh.net/projects/3459">Code Statistics</a></li>
  524. </ul>
  525. </div>
  526. <div class="MenuGroup">
  527. <h1>Using XStream</h1>
  528. <ul>
  529. <li><a href="architecture.html">Architecture Overview</a></li>
  530. <li><a href="converters.html">Converters</a></li>
  531. <li><a href="faq.html">Frequently Asked Questions</a></li>
  532. <li><a href="list-user.html">Users' Mailing List</a></li>
  533. <li><a href="issues.html">Reporting Issues</a></li>
  534. </ul>
  535. </div>
  536. <div class="MenuGroup">
  537. <h1>Javadoc</h1>
  538. <ul>
  539. <li><a href="javadoc/index.html">XStream Core</a></li>
  540. <li><a href="hibernate-javadoc/index.html">Hibernate Extensions</a></li>
  541. <li><a href="benchmark-javadoc/index.html">Benchmark Module</a></li>
  542. </ul>
  543. </div>
  544. <div class="MenuGroup">
  545. <h1>Tutorials</h1>
  546. <ul>
  547. <li><a href="tutorial.html">Two Minute Tutorial</a></li>
  548. <li><a href="alias-tutorial.html">Alias Tutorial</a></li>
  549. <li><a href="annotations-tutorial.html">Annotations Tutorial</a></li>
  550. <li class="currentLink">Converter Tutorial</li>
  551. <li><a href="objectstream.html">Object Streams Tutorial</a></li>
  552. <li><a href="persistence-tutorial.html">Persistence API Tutorial</a></li>
  553. <li><a href="json-tutorial.html">JSON Tutorial</a></li>
  554. </ul>
  555. </div>
  556. <div class="MenuGroup">
  557. <h1>Developing XStream</h1>
  558. <ul>
  559. <li><a href="how-to-contribute.html">How to Contribute</a></li>
  560. <li><a href="list-dev.html">Developers' Mailing List</a></li>
  561. <li><a href="team.html">Development Team</a></li>
  562. <li><a href="repository.html">Source Repository</a></li>
  563. <li><a href="http://bamboo.ci.codehaus.org/browse/XSTREAM">Continuous Integration</a></li>
  564. </ul>
  565. </div>
  566. </div>
  567. </body>
  568. </html>