001: /*
002: * Copyright (C) 2007 XStream Committers.
003: * All rights reserved.
004: *
005: * The software in this package is published under the terms of the BSD
006: * style license a copy of which has been included with this distribution in
007: * the LICENSE.txt file.
008: *
009: * Created on 23. November 2007 by Joerg Schaible
010: */
011: package com.thoughtworks.acceptance.annotations;
012:
013: import com.thoughtworks.acceptance.AbstractAcceptanceTest;
014: import com.thoughtworks.xstream.XStream;
015: import com.thoughtworks.xstream.annotations.XStreamAlias;
016: import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
017: import com.thoughtworks.xstream.annotations.XStreamConverter;
018: import com.thoughtworks.xstream.converters.Converter;
019: import com.thoughtworks.xstream.converters.MarshallingContext;
020: import com.thoughtworks.xstream.converters.UnmarshallingContext;
021: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
022: import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
023:
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.List;
027: import java.util.Map;
028:
029: /**
030: * Tests annotations defining aliases for classes or fields.
031: *
032: * @author Chung-Onn Cheong
033: * @author Mauro Talevi
034: * @author Guilherme Silveira
035: * @author Jörg Schaible
036: */
037: public class AliasTest extends AbstractAcceptanceTest {
038:
039: @Override
040: protected XStream createXStream() {
041: XStream xstream = super .createXStream();
042: xstream.autodetectAnnotations(true);
043: return xstream;
044: }
045:
046: public void testAnnotationForClassWithAnnotatedConverter() {
047: Map<String, Person> map = new HashMap<String, Person>();
048: map.put("first person", new Person("john doe"));
049: map.put("second person", new Person("jane doe"));
050: String xml = "" + "<map>\n" + " <entry>\n"
051: + " <string>second person</string>\n"
052: + " <person>jane doe</person>\n" + " </entry>\n"
053: + " <entry>\n" + " <string>first person</string>\n"
054: + " <person>john doe</person>\n" + " </entry>\n"
055: + "</map>";
056: assertBothWaysNormalized(map, xml, "map", "entry", "string");
057: }
058:
059: public void testAnnotationForFieldWithAliasCycle() {
060: Cycle cycle = new Cycle();
061: cycle.internal = cycle;
062: String xml = "" //
063: + "<cycle>\n" //
064: + " <oops reference=\"..\"/>\n" //
065: + "</cycle>";
066: assertBothWays(cycle, xml);
067: }
068:
069: @XStreamAlias("cycle")
070: public static class Cycle {
071: @XStreamAlias("oops")
072: private Cycle internal;
073: }
074:
075: public void testAnnotationForField() {
076: List<String> nickNames = new ArrayList<String>();
077: nickNames.add("johnny");
078: nickNames.add("jack");
079: CustomPerson person = new CustomPerson("john", "doe", 25,
080: nickNames);
081: String expectedXml = "" + "<person>\n"
082: + " <first-name>john</first-name>\n"
083: + " <last-name>doe</last-name>\n"
084: + " <age-in-years>25</age-in-years>\n"
085: + " <nick-names>\n" + " <string>johnny</string>\n"
086: + " <string>jack</string>\n" + " </nick-names>\n"
087: + "</person>";
088: assertBothWays(person, expectedXml);
089: }
090:
091: @XStreamAlias("person")
092: public static class CustomPerson {
093: @XStreamAlias("first-name")
094: String firstName;
095: @XStreamAlias("last-name")
096: String lastName;
097: @XStreamAlias("age-in-years")
098: int ageInYears;
099: @XStreamAlias("nick-names")
100: List<String> nickNames;
101:
102: public CustomPerson(String firstName, String lastName,
103: int ageInYears, List<String> nickNames) {
104: this .firstName = firstName;
105: this .lastName = lastName;
106: this .ageInYears = ageInYears;
107: this .nickNames = nickNames;
108: }
109:
110: public boolean equals(Object obj) {
111: if ((obj == null) || !(obj instanceof CustomPerson))
112: return false;
113: return toString().equals(obj.toString());
114: }
115:
116: @Override
117: public String toString() {
118: StringBuilder sb = new StringBuilder();
119: sb.append("firstName:").append(firstName).append(
120: ",lastName:").append(lastName).append(
121: ",ageInYears:").append(ageInYears).append(
122: ",nickNames:").append(nickNames);
123: return sb.toString();
124: }
125:
126: }
127:
128: @XStreamAlias("person")
129: @XStreamConverter(PersonConverter.class)
130: public static class Person {
131: String name;
132: AddressBookInfo addressBook;
133:
134: public Person(String name) {
135: this .name = name;
136: addressBook = new AddressBook();
137: }
138:
139: public boolean equals(Object obj) {
140: if ((obj == null) || !(obj instanceof Person))
141: return false;
142: return addressBook.equals(((Person) obj).addressBook);
143: }
144:
145: @Override
146: public String toString() {
147: StringBuilder sb = new StringBuilder();
148: sb.append("name:").append(name).append("addresbook:")
149: .append(addressBook);
150: return sb.toString();
151: }
152:
153: }
154:
155: @XStreamAlias(value="addressbook-info",impl=AddressBook.class)
156: public interface AddressBookInfo {
157: public List<AddressInfo> getAddresses();
158:
159: public void setAddresses(List<AddressInfo> address);
160: }
161:
162: @XStreamAlias("addressbookAlias")
163: public static class AddressBook implements AddressBookInfo {
164:
165: // @XStreamContainedType
166: private List<AddressInfo> addresses;
167:
168: public AddressBook() {
169: addresses = new ArrayList<AddressInfo>();
170: addresses.add(new Address("Home Address", 111));
171: addresses.add(new Address("Office Address", 222));
172: }
173:
174: public List<AddressInfo> getAddresses() {
175: return addresses;
176: }
177:
178: public void setAddresses(List<AddressInfo> addresses) {
179: this .addresses = addresses;
180:
181: }
182:
183: public boolean equals(Object obj) {
184: if ((obj == null) || !(obj instanceof AddressBookInfo))
185: return false;
186: return addresses.containsAll(((AddressBookInfo) obj)
187: .getAddresses());
188: }
189:
190: }
191:
192: @XStreamAlias(value="addressinfoAlias",impl=Address.class)
193: public interface AddressInfo {
194: public String addr();
195:
196: public int zipcode();
197: }
198:
199: @XStreamAlias(value="addressAlias")
200: public static class Address implements AddressInfo {
201:
202: private String addr;
203: private int zipcode;
204:
205: public Address(String addr, int zipcode) {
206: this .addr = addr;
207: this .zipcode = zipcode;
208: }
209:
210: public String addr() {
211: return addr;
212: }
213:
214: public int zipcode() {
215: return zipcode;
216: }
217:
218: }
219:
220: public static class PersonConverter implements Converter {
221: public PersonConverter() {
222: }
223:
224: public String toString(Object obj) {
225: return ((Person) obj).name;
226: }
227:
228: public Object fromString(String str) {
229: return new Person(str);
230: }
231:
232: public boolean canConvert(Class type) {
233: return type == Person.class;
234: }
235:
236: public void marshal(Object source,
237: HierarchicalStreamWriter writer,
238: MarshallingContext context) {
239: writer.setValue(toString(source));
240: }
241:
242: public Object unmarshal(HierarchicalStreamReader reader,
243: UnmarshallingContext context) {
244: return fromString(reader.getValue());
245: }
246: }
247:
248: static class Dash {
249:
250: @XStreamAlias("camel-case")
251: int camelCase = 5;
252: }
253:
254: public void testAnnotationForFieldWithAttributeDefinitionForFieldType() {
255: xstream.alias("dash", Dash.class);
256: xstream.useAttributeFor(int.class);
257: String xml = "<dash camel-case=\"5\"/>";
258: assertBothWays(new Dash(), xml);
259: }
260:
261: public static abstract class Aged {
262: @XStreamAlias("age")
263: @XStreamAsAttribute
264: private Integer id;
265:
266: Aged(Integer id) {
267: this .id = id;
268: }
269: }
270:
271: @XStreamAlias("thing")
272: public static class AgedThing extends Aged {
273:
274: @XStreamAsAttribute
275: private String name;
276:
277: AgedThing(String name, Integer id) {
278: super (id);
279: this .name = name;
280: }
281: }
282:
283: public void testAnnotationIsInheritedTogetherWithAsAttribute() {
284: String xml = "<thing age=\"99\" name=\"Name\"/>";
285: assertBothWays(new AgedThing("Name", 99), xml);
286: }
287: }
|