1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.oxm.jaxb;
18
19 import java.awt.*;
20 import java.io.ByteArrayOutputStream;
21 import java.io.StringWriter;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.ParameterizedType;
24 import java.lang.reflect.Type;
25 import java.math.BigDecimal;
26 import java.math.BigInteger;
27 import java.net.URI;
28 import java.util.Calendar;
29 import java.util.Collections;
30 import java.util.Date;
31 import java.util.UUID;
32 import javax.activation.DataHandler;
33 import javax.activation.FileDataSource;
34 import javax.xml.bind.JAXBElement;
35 import javax.xml.datatype.Duration;
36 import javax.xml.datatype.XMLGregorianCalendar;
37 import javax.xml.namespace.QName;
38 import javax.xml.parsers.DocumentBuilder;
39 import javax.xml.parsers.DocumentBuilderFactory;
40 import javax.xml.stream.XMLEventWriter;
41 import javax.xml.stream.XMLOutputFactory;
42 import javax.xml.stream.XMLStreamWriter;
43 import javax.xml.transform.Result;
44 import javax.xml.transform.Source;
45 import javax.xml.transform.dom.DOMResult;
46 import javax.xml.transform.sax.SAXResult;
47 import javax.xml.transform.stax.StAXResult;
48 import javax.xml.transform.stream.StreamResult;
49
50 import org.custommonkey.xmlunit.XMLTestCase;
51 import static org.easymock.EasyMock.*;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Element;
54 import org.w3c.dom.Text;
55 import org.xml.sax.Attributes;
56 import org.xml.sax.ContentHandler;
57 import org.xml.sax.Locator;
58
59 import org.springframework.core.io.ClassPathResource;
60 import org.springframework.core.io.Resource;
61 import org.springframework.oxm.XmlMappingException;
62 import org.springframework.oxm.jaxb2.FlightType;
63 import org.springframework.oxm.jaxb2.Flights;
64 import org.springframework.oxm.jaxb2.ObjectFactory;
65 import org.springframework.oxm.mime.MimeContainer;
66 import org.springframework.util.FileCopyUtils;
67 import org.springframework.xml.transform.StaxResult;
68 import org.springframework.xml.transform.StringResult;
69
70 public class Jaxb2MarshallerTest extends XMLTestCase {
71
72 private static final String CONTEXT_PATH = "org.springframework.oxm.jaxb2";
73
74 private static final String EXPECTED_STRING =
75 "<tns:flights xmlns:tns=\"http://samples.springframework.org/flight\">" +
76 "<tns:flight><tns:number>42</tns:number></tns:flight></tns:flights>";
77
78 private Jaxb2Marshaller marshaller;
79
80 private Flights flights;
81
82 protected void setUp() throws Exception {
83 marshaller = new Jaxb2Marshaller();
84 marshaller.setContextPath(CONTEXT_PATH);
85 marshaller.afterPropertiesSet();
86 FlightType flight = new FlightType();
87 flight.setNumber(42L);
88 flights = new Flights();
89 flights.getFlight().add(flight);
90 }
91
92 public void testMarshalDOMResult() throws Exception {
93 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
94 DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
95 Document document = builder.newDocument();
96 DOMResult domResult = new DOMResult(document);
97 marshaller.marshal(flights, domResult);
98 Document expected = builder.newDocument();
99 Element flightsElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:flights");
100 expected.appendChild(flightsElement);
101 Element flightElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:flight");
102 flightsElement.appendChild(flightElement);
103 Element numberElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:number");
104 flightElement.appendChild(numberElement);
105 Text text = expected.createTextNode("42");
106 numberElement.appendChild(text);
107 assertXMLEqual("Marshaller writes invalid DOMResult", expected, document);
108 }
109
110 public void testMarshalStreamResultWriter() throws Exception {
111 StringWriter writer = new StringWriter();
112 StreamResult result = new StreamResult(writer);
113 marshaller.marshal(flights, result);
114 assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString());
115 }
116
117 public void testMarshalStreamResultOutputStream() throws Exception {
118 ByteArrayOutputStream os = new ByteArrayOutputStream();
119 StreamResult result = new StreamResult(os);
120 marshaller.marshal(flights, result);
121 assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING,
122 new String(os.toByteArray(), "UTF-8"));
123 }
124
125 public void testMarshalStaxResultXMLStreamWriter() throws Exception {
126 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
127 StringWriter writer = new StringWriter();
128 XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer);
129 StaxResult result = new StaxResult(streamWriter);
130 marshaller.marshal(flights, result);
131 assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString());
132 }
133
134 public void testMarshalStaxResultXMLEventWriter() throws Exception {
135 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
136 StringWriter writer = new StringWriter();
137 XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);
138 StaxResult result = new StaxResult(eventWriter);
139 marshaller.marshal(flights, result);
140 assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString());
141 }
142
143 public void testMarshalStaxResultXMLStreamWriterJaxp14() throws Exception {
144 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
145 StringWriter writer = new StringWriter();
146 XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer);
147 StAXResult result = new StAXResult(streamWriter);
148 marshaller.marshal(flights, result);
149 assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString());
150 }
151
152 public void testMarshalStaxResultXMLEventWriterJaxp14() throws Exception {
153 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
154 StringWriter writer = new StringWriter();
155 XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);
156 StAXResult result = new StAXResult(eventWriter);
157 marshaller.marshal(flights, result);
158 assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString());
159 }
160
161 public void testProperties() throws Exception {
162 Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
163 marshaller.setContextPath(CONTEXT_PATH);
164 marshaller.setMarshallerProperties(
165 Collections.singletonMap(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE));
166 marshaller.afterPropertiesSet();
167 }
168
169 public void testNoContextPathOrClassesToBeBound() throws Exception {
170 try {
171 Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
172 marshaller.afterPropertiesSet();
173 fail("Should have thrown an IllegalArgumentException");
174 }
175 catch (IllegalArgumentException e) {
176 }
177 }
178
179 public void testInvalidContextPath() throws Exception {
180 try {
181 Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
182 marshaller.setContextPath("ab");
183 marshaller.afterPropertiesSet();
184 fail("Should have thrown an XmlMappingException");
185 }
186 catch (XmlMappingException ex) {
187 }
188 }
189
190 public void testMarshalInvalidClass() throws Exception {
191 Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
192 marshaller.setClassesToBeBound(new Class[]{FlightType.class});
193 marshaller.afterPropertiesSet();
194 Result result = new StreamResult(new StringWriter());
195 Flights flights = new Flights();
196 try {
197 marshaller.marshal(flights, result);
198 fail("Should have thrown an MarshallingFailureException");
199 }
200 catch (XmlMappingException ex) {
201
202 }
203 }
204
205 public void testMarshalSaxResult() throws Exception {
206 ContentHandler handlerMock = createStrictMock(ContentHandler.class);
207 handlerMock.setDocumentLocator(isA(Locator.class));
208 handlerMock.startDocument();
209 handlerMock.startPrefixMapping("", "http://samples.springframework.org/flight");
210 handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("flights"), eq("flights"),
211 isA(Attributes.class));
212 handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("flight"), eq("flight"),
213 isA(Attributes.class));
214 handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("number"), eq("number"),
215 isA(Attributes.class));
216 handlerMock.characters(isA(char[].class), eq(0), eq(2));
217 handlerMock.endElement("http://samples.springframework.org/flight", "number", "number");
218 handlerMock.endElement("http://samples.springframework.org/flight", "flight", "flight");
219 handlerMock.endElement("http://samples.springframework.org/flight", "flights", "flights");
220 handlerMock.endPrefixMapping("");
221 handlerMock.endDocument();
222 replay(handlerMock);
223
224 SAXResult result = new SAXResult(handlerMock);
225 marshaller.marshal(flights, result);
226 verify(handlerMock);
227 }
228
229 public void testSupportsContextPath() throws Exception {
230 Method createFlights = ObjectFactory.class.getDeclaredMethod("createFlights");
231 assertTrue("Jaxb2Marshaller does not support Flights",
232 marshaller.supports(createFlights.getGenericReturnType()));
233 Method createFlight = ObjectFactory.class.getDeclaredMethod("createFlight", FlightType.class);
234 assertTrue("Jaxb2Marshaller does not support JAXBElement<FlightsType>",
235 marshaller.supports(createFlight.getGenericReturnType()));
236 assertFalse("Jaxb2Marshaller supports non-parameterized JAXBElement", marshaller.supports(JAXBElement.class));
237 JAXBElement<Jaxb2MarshallerTest> testElement =
238 new JAXBElement<Jaxb2MarshallerTest>(new QName("something"), Jaxb2MarshallerTest.class, null, this);
239 assertFalse("Jaxb2Marshaller supports wrong JAXBElement", marshaller.supports(testElement.getClass()));
240 }
241
242 public void testSupportsClassesToBeBound() throws Exception {
243 marshaller = new Jaxb2Marshaller();
244 marshaller.setClassesToBeBound(new Class[]{Flights.class, FlightType.class});
245 marshaller.afterPropertiesSet();
246 Method createFlights = ObjectFactory.class.getDeclaredMethod("createFlights");
247 assertTrue("Jaxb2Marshaller does not support Flights",
248 marshaller.supports(createFlights.getGenericReturnType()));
249 Method createFlight = ObjectFactory.class.getDeclaredMethod("createFlight", FlightType.class);
250 assertTrue("Jaxb2Marshaller does not support JAXBElement<FlightsType>",
251 marshaller.supports(createFlight.getGenericReturnType()));
252 assertFalse("Jaxb2Marshaller supports non-parameterized JAXBElement", marshaller.supports(JAXBElement.class));
253 JAXBElement<Jaxb2MarshallerTest> testElement =
254 new JAXBElement<Jaxb2MarshallerTest>(new QName("something"), Jaxb2MarshallerTest.class, null, this);
255 assertFalse("Jaxb2Marshaller supports wrong JAXBElement", marshaller.supports(testElement.getClass()));
256 }
257
258 public void testSupportsPrimitives() throws Exception {
259 Method primitives = getClass().getDeclaredMethod("primitives", JAXBElement.class, JAXBElement.class,
260 JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class,
261 JAXBElement.class);
262 Type[] types = primitives.getGenericParameterTypes();
263 for (int i = 0; i < types.length; i++) {
264 ParameterizedType type = (ParameterizedType) types[i];
265 assertTrue("Jaxb2Marshaller does not support " + type, marshaller.supports(types[i]));
266 }
267 }
268
269 public void testSupportsStandards() throws Exception {
270 Method standards = getClass().getDeclaredMethod("standards", JAXBElement.class, JAXBElement.class,
271 JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class,
272 JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class,
273 JAXBElement.class, JAXBElement.class);
274 Type[] types = standards.getGenericParameterTypes();
275 for (int i = 0; i < types.length; i++) {
276 ParameterizedType type = (ParameterizedType) types[i];
277 assertTrue("Jaxb2Marshaller does not support " + type, marshaller.supports(types[i]));
278 }
279 }
280
281 public void testMarshalAttachments() throws Exception {
282 marshaller = new Jaxb2Marshaller();
283 marshaller.setClassesToBeBound(new Class[]{BinaryObject.class});
284 marshaller.setMtomEnabled(true);
285 marshaller.afterPropertiesSet();
286 MimeContainer mimeContainer = createMock(MimeContainer.class);
287
288 Resource logo = new ClassPathResource("spring-ws.png", getClass());
289 DataHandler dataHandler = new DataHandler(new FileDataSource(logo.getFile()));
290
291 expect(mimeContainer.convertToXopPackage()).andReturn(true);
292 mimeContainer.addAttachment(isA(String.class), isA(DataHandler.class));
293 expectLastCall().times(3);
294
295 replay(mimeContainer);
296 byte[] bytes = FileCopyUtils.copyToByteArray(logo.getInputStream());
297 BinaryObject object = new BinaryObject(bytes, dataHandler);
298 Result result = new StringResult();
299 marshaller.marshal(object, result, mimeContainer);
300 verify(mimeContainer);
301 assertTrue("No XML written", result.toString().length() > 0);
302 }
303
304 private void primitives(JAXBElement<Boolean> bool,
305 JAXBElement<Byte> aByte,
306 JAXBElement<Short> aShort,
307 JAXBElement<Integer> anInteger,
308 JAXBElement<Long> aLong,
309 JAXBElement<Float> aFloat,
310 JAXBElement<Double> aDouble,
311 JAXBElement<byte[]> byteArray) {
312 }
313
314 private void standards(JAXBElement<String> string,
315 JAXBElement<BigInteger> integer,
316 JAXBElement<BigDecimal> decimal,
317 JAXBElement<Calendar> calendar,
318 JAXBElement<Date> date,
319 JAXBElement<QName> qName,
320 JAXBElement<URI> uri,
321 JAXBElement<XMLGregorianCalendar> xmlGregorianCalendar,
322 JAXBElement<Duration> duration,
323 JAXBElement<Object> object,
324 JAXBElement<Image> image,
325 JAXBElement<DataHandler> dataHandler,
326 JAXBElement<Source> source,
327 JAXBElement<UUID> uuid) {
328 }
329 }