001: /*
002: * Copyright (C) 2006 Joe Walnes.
003: * Copyright (C) 2006, 2007, 2008 XStream Committers.
004: * All rights reserved.
005: *
006: * The software in this package is published under the terms of the BSD
007: * style license a copy of which has been included with this distribution in
008: * the LICENSE.txt file.
009: *
010: * Created on 02. March 2006 by Mauro Talevi
011: */
012: package com.thoughtworks.acceptance.annotations;
013:
014: import com.thoughtworks.acceptance.AbstractAcceptanceTest;
015: import com.thoughtworks.xstream.XStream;
016: import com.thoughtworks.xstream.annotations.XStreamConverter;
017: import com.thoughtworks.xstream.converters.Converter;
018: import com.thoughtworks.xstream.converters.MarshallingContext;
019: import com.thoughtworks.xstream.converters.UnmarshallingContext;
020: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
021: import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
022:
023: /**
024: * Tests for using annotations to override field converters
025: *
026: * @author Guilherme Silveira
027: * @author Mauro Talevi
028: * @author Jörg Schaible
029: */
030: public class FieldConverterTest extends AbstractAcceptanceTest {
031:
032: @Override
033: protected XStream createXStream() {
034: XStream xstream = super .createXStream();
035: xstream.autodetectAnnotations(true);
036: return xstream;
037: }
038:
039: protected void setUp() throws Exception {
040: super .setUp();
041: xstream.alias("annotatedTask", TaskWithAnnotations.class);
042: xstream.alias("derivedTask", DerivedTask.class);
043: xstream.alias("taskContainer", TaskContainer.class);
044: }
045:
046: public void testAnnotationForFieldsOfSameType() {
047: final TaskWithAnnotations task = new TaskWithAnnotations("Tom",
048: "Dick", "Harry");
049: final String xml = "" + "<annotatedTask>\n"
050: + " <name1 str=\"Tom\"/>\n"
051: + " <name2>_Dick_</name2>\n"
052: + " <name3>Harry</name3>\n" + "</annotatedTask>";
053: assertBothWays(task, xml);
054: }
055:
056: public void testAnnotationForHiddenFields() {
057: final DerivedTask task = new DerivedTask("Tom", "Dick", "Harry");
058: final String xml = ""
059: + "<derivedTask>\n"
060: + " <name1 defined-in=\"annotatedTask\" str=\"Tom\"/>\n"
061: + " <name2>_Dick_</name2>\n"
062: + " <name3 defined-in=\"annotatedTask\">Harry</name3>\n"
063: + " <name1>Harry</name1>\n"
064: + " <name3 str=\"Tom\"/>\n" + "</derivedTask>";
065: assertBothWays(task, xml);
066: }
067:
068: public void testIsFoundInReferencedTypes() {
069: final TaskContainer taskContainer = new TaskContainer();
070: final String xml = ""
071: + "<taskContainer>\n"
072: + " <task>\n"
073: + " <name1 defined-in=\"annotatedTask\" str=\"Tom\"/>\n"
074: + " <name2>_Dick_</name2>\n"
075: + " <name3 defined-in=\"annotatedTask\">Harry</name3>\n"
076: + " <name1>Harry</name1>\n"
077: + " <name3 str=\"Tom\"/>\n" + " </task>\n"
078: + "</taskContainer>";
079: assertEquals(taskContainer, xstream.fromXML(xml));
080: }
081:
082: public static class TaskWithAnnotations {
083:
084: @XStreamConverter(FirstConverter.class)
085: private final String name1;
086:
087: @XStreamConverter(SecondaryConverter.class)
088: private final String name2;
089: private final String name3;
090:
091: public TaskWithAnnotations(final String name1,
092: final String name2, final String name3) {
093: this .name1 = name1;
094: this .name2 = name2;
095: this .name3 = name3;
096: }
097:
098: @Override
099: public boolean equals(final Object obj) {
100: return obj != null
101: && TaskWithAnnotations.class.isAssignableFrom(obj
102: .getClass())
103: && ((TaskWithAnnotations) obj).name1.equals(name1)
104: && ((TaskWithAnnotations) obj).name2.equals(name2)
105: && ((TaskWithAnnotations) obj).name3.equals(name3);
106: }
107: }
108:
109: public static class DerivedTask extends TaskWithAnnotations {
110: private final String name1;
111:
112: @XStreamConverter(FirstConverter.class)
113: private final String name3;
114:
115: public DerivedTask(final String name1, final String name2,
116: final String name3) {
117: super (name1, name2, name3);
118: this .name1 = name3;
119: this .name3 = name1;
120: }
121:
122: @Override
123: public boolean equals(final Object obj) {
124: return obj != null
125: && DerivedTask.class.isAssignableFrom(obj
126: .getClass())
127: && ((DerivedTask) obj).name1.equals(name1)
128: && ((DerivedTask) obj).name3.equals(name3)
129: && super .equals(obj);
130: }
131: }
132:
133: public static class TaskContainer {
134: private final DerivedTask task = new DerivedTask("Tom", "Dick",
135: "Harry");
136:
137: @Override
138: public boolean equals(final Object obj) {
139: return obj != null
140: && TaskContainer.class.equals(obj.getClass())
141: && task.equals(((TaskContainer) obj).task);
142: }
143: }
144:
145: public static class FirstConverter implements Converter {
146:
147: public void marshal(final Object source,
148: final HierarchicalStreamWriter writer,
149: final MarshallingContext context) {
150: final String str = source.toString();
151: writer.addAttribute("str", str);
152: }
153:
154: public Object unmarshal(final HierarchicalStreamReader reader,
155: final UnmarshallingContext context) {
156: final String str = reader.getAttribute("str");
157: return str;
158: }
159:
160: public boolean canConvert(final Class type) {
161: return type.equals(String.class);
162: }
163: }
164:
165: public static class SecondaryConverter implements Converter {
166:
167: public void marshal(final Object source,
168: final HierarchicalStreamWriter writer,
169: final MarshallingContext context) {
170: writer.setValue("_" + source.toString() + "_");
171: }
172:
173: public Object unmarshal(final HierarchicalStreamReader reader,
174: final UnmarshallingContext context) {
175: final String value = reader.getValue();
176: return value.substring(1, value.length() - 1);
177: }
178:
179: public boolean canConvert(final Class type) {
180: return type.equals(String.class);
181: }
182: }
183:
184: public static class CustomConverter implements Converter {
185:
186: private static int total = 0;
187:
188: public CustomConverter() {
189: total++;
190: }
191:
192: public void marshal(Object source,
193: HierarchicalStreamWriter writer,
194: MarshallingContext context) {
195: }
196:
197: public Object unmarshal(HierarchicalStreamReader reader,
198: UnmarshallingContext context) {
199: return null;
200: }
201:
202: public boolean canConvert(Class type) {
203: return type.equals(Double.class);
204: }
205:
206: }
207:
208: public static class Account {
209: @XStreamConverter(CustomConverter.class)
210: private Double value;
211:
212: public Account() {
213: this .value = Math.random();
214: }
215: }
216:
217: public static class Client {
218: @XStreamConverter(CustomConverter.class)
219: private Double value;
220:
221: public Client() {
222: this .value = Math.random();
223: }
224: }
225:
226: public void testAreCachedPerField() {
227: int before = CustomConverter.total;
228: toXML(new Account());
229: int after = CustomConverter.total;
230: assertEquals(before + 1, after);
231: }
232:
233: public void testAreCachedPerFieldInDifferentContexts() {
234: int before = CustomConverter.total;
235: toXML(new Account());
236: toXML(new Client());
237: int after = CustomConverter.total;
238: assertEquals(before + 1, after);
239: }
240:
241: }
|