1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.oxm.xstream;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.io.OutputStream;
23 import java.io.OutputStreamWriter;
24 import java.io.Reader;
25 import java.io.Writer;
26 import java.util.Iterator;
27 import java.util.Map;
28 import javax.xml.stream.XMLEventReader;
29 import javax.xml.stream.XMLEventWriter;
30 import javax.xml.stream.XMLStreamException;
31 import javax.xml.stream.XMLStreamReader;
32 import javax.xml.stream.XMLStreamWriter;
33
34 import com.thoughtworks.xstream.XStream;
35 import com.thoughtworks.xstream.converters.Converter;
36 import com.thoughtworks.xstream.converters.ConverterMatcher;
37 import com.thoughtworks.xstream.converters.SingleValueConverter;
38 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
39 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
40 import com.thoughtworks.xstream.io.xml.CompactWriter;
41 import com.thoughtworks.xstream.io.xml.DomReader;
42 import com.thoughtworks.xstream.io.xml.DomWriter;
43 import com.thoughtworks.xstream.io.xml.QNameMap;
44 import com.thoughtworks.xstream.io.xml.SaxWriter;
45 import com.thoughtworks.xstream.io.xml.StaxReader;
46 import com.thoughtworks.xstream.io.xml.StaxWriter;
47 import com.thoughtworks.xstream.io.xml.XppReader;
48 import org.springframework.beans.propertyeditors.ClassEditor;
49 import org.springframework.oxm.AbstractMarshaller;
50 import org.springframework.oxm.XmlMappingException;
51 import org.springframework.util.ObjectUtils;
52 import org.springframework.xml.stream.StaxEventContentHandler;
53 import org.springframework.xml.stream.XmlEventStreamReader;
54 import org.w3c.dom.Document;
55 import org.w3c.dom.Element;
56 import org.w3c.dom.Node;
57 import org.xml.sax.ContentHandler;
58 import org.xml.sax.InputSource;
59 import org.xml.sax.XMLReader;
60 import org.xml.sax.ext.LexicalHandler;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public class XStreamMarshaller extends AbstractMarshaller {
81
82
83 public static final String DEFAULT_ENCODING = "UTF-8";
84
85 private XStream xstream = new XStream();
86
87 private String encoding;
88
89 private Class[] supportedClasses;
90
91
92
93
94
95
96 public String getEncoding() {
97 return encoding != null ? encoding : DEFAULT_ENCODING;
98 }
99
100
101
102
103
104
105 public void setEncoding(String encoding) {
106 this.encoding = encoding;
107 }
108
109
110 public XStream getXStream() {
111 return xstream;
112 }
113
114
115
116
117
118
119
120
121 public void setMode(int mode) {
122 getXStream().setMode(mode);
123 }
124
125
126
127
128
129
130
131 public void setSupportedClasses(Class[] supportedClasses) {
132 this.supportedClasses = supportedClasses;
133 }
134
135
136
137
138
139
140
141
142 public void setConverters(ConverterMatcher[] converters) {
143 for (int i = 0; i < converters.length; i++) {
144 if (converters[i] instanceof Converter) {
145 getXStream().registerConverter((Converter) converters[i], i);
146 }
147 else if (converters[i] instanceof SingleValueConverter) {
148 getXStream().registerConverter((SingleValueConverter) converters[i], i);
149 }
150 else {
151 throw new IllegalArgumentException("Invalid ConverterMatcher [" + converters[i] + "]");
152 }
153 }
154 }
155
156
157
158
159
160
161
162 public void setAliases(Map aliases) {
163 for (Iterator iterator = aliases.entrySet().iterator(); iterator.hasNext();) {
164 Map.Entry entry = (Map.Entry) iterator.next();
165
166 Class type;
167 if (entry.getValue() instanceof Class) {
168 type = (Class) entry.getValue();
169 }
170 else {
171 ClassEditor editor = new ClassEditor();
172 editor.setAsText(String.valueOf(entry.getValue()));
173 type = (Class) editor.getValue();
174 }
175 addAlias((String) entry.getKey(), type);
176 }
177 }
178
179
180
181
182
183
184
185 public void addAlias(String name, Class type) {
186 getXStream().alias(name, type);
187 }
188
189
190
191
192
193
194 public void setUseAttributeForTypes(Class[] types) {
195 for (int i = 0; i < types.length; i++) {
196 getXStream().useAttributeFor(types[i]);
197 }
198 }
199
200
201
202
203
204
205 public void setUseAttributeFor(Map attributes) {
206 for (Iterator iterator = attributes.entrySet().iterator(); iterator.hasNext();) {
207 Map.Entry entry = (Map.Entry) iterator.next();
208 if (entry.getKey() instanceof String && entry.getValue() instanceof Class) {
209 getXStream().useAttributeFor((String) entry.getKey(), (Class) entry.getValue());
210 }
211 else if (entry.getKey() instanceof Class && entry.getValue() instanceof String) {
212 getXStream().useAttributeFor((Class) entry.getKey(), (String) entry.getValue());
213 }
214 else {
215 throw new IllegalArgumentException("Invalid attribute key and value pair. " +
216 "'useAttributesFor' property takes either a <String, Class> map or a <Class, String> map");
217 }
218 }
219 }
220
221 public boolean supports(Class clazz) {
222 if (ObjectUtils.isEmpty(supportedClasses)) {
223 return true;
224 }
225 else {
226 for (int i = 0; i < supportedClasses.length; i++) {
227 if (supportedClasses[i].isAssignableFrom(clazz)) {
228 return true;
229 }
230 }
231 return false;
232 }
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246
247 public XmlMappingException convertXStreamException(Exception ex, boolean marshalling) {
248 return XStreamUtils.convertXStreamException(ex, marshalling);
249 }
250
251
252
253
254
255 private void marshal(Object graph, HierarchicalStreamWriter streamWriter) {
256 try {
257 getXStream().marshal(graph, streamWriter);
258 }
259 catch (Exception ex) {
260 throw convertXStreamException(ex, true);
261 }
262 }
263
264 protected void marshalDomNode(Object graph, Node node) throws XmlMappingException {
265 HierarchicalStreamWriter streamWriter;
266 if (node instanceof Document) {
267 streamWriter = new DomWriter((Document) node);
268 }
269 else if (node instanceof Element) {
270 streamWriter = new DomWriter((Element) node);
271 }
272 else {
273 throw new IllegalArgumentException("DOMResult contains neither Document nor Element");
274 }
275 marshal(graph, streamWriter);
276 }
277
278 protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
279 ContentHandler contentHandler = new StaxEventContentHandler(eventWriter);
280 marshalSaxHandlers(graph, contentHandler, null);
281 }
282
283 protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
284 try {
285 marshal(graph, new StaxWriter(new QNameMap(), streamWriter));
286 }
287 catch (XMLStreamException ex) {
288 throw convertXStreamException(ex, true);
289 }
290 }
291
292 protected void marshalOutputStream(Object graph, OutputStream outputStream)
293 throws XmlMappingException, IOException {
294 marshalWriter(graph, new OutputStreamWriter(outputStream, getEncoding()));
295 }
296
297 protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler)
298 throws XmlMappingException {
299 SaxWriter saxWriter = new SaxWriter();
300 saxWriter.setContentHandler(contentHandler);
301 marshal(graph, saxWriter);
302 }
303
304 protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
305 marshal(graph, new CompactWriter(writer));
306 }
307
308 private Object unmarshal(HierarchicalStreamReader streamReader) {
309 try {
310 return getXStream().unmarshal(streamReader);
311 }
312 catch (Exception ex) {
313 throw convertXStreamException(ex, false);
314 }
315 }
316
317 protected Object unmarshalDomNode(Node node) throws XmlMappingException {
318 HierarchicalStreamReader streamReader;
319 if (node instanceof Document) {
320 streamReader = new DomReader((Document) node);
321 }
322 else if (node instanceof Element) {
323 streamReader = new DomReader((Element) node);
324 }
325 else {
326 throw new IllegalArgumentException("DOMSource contains neither Document nor Element");
327 }
328 return unmarshal(streamReader);
329 }
330
331 protected Object unmarshalXmlEventReader(XMLEventReader eventReader) throws XmlMappingException {
332 try {
333 XMLStreamReader streamReader = new XmlEventStreamReader(eventReader);
334 return unmarshalXmlStreamReader(streamReader);
335 }
336 catch (XMLStreamException ex) {
337 throw convertXStreamException(ex, false);
338 }
339 }
340
341 protected Object unmarshalXmlStreamReader(XMLStreamReader streamReader) throws XmlMappingException {
342 return unmarshal(new StaxReader(new QNameMap(), streamReader));
343 }
344
345 protected Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException {
346 return unmarshalReader(new InputStreamReader(inputStream, getEncoding()));
347 }
348
349 protected Object unmarshalReader(Reader reader) throws XmlMappingException, IOException {
350 return unmarshal(new XppReader(reader));
351 }
352
353 protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
354 throws XmlMappingException, IOException {
355 throw new UnsupportedOperationException(
356 "XStreamMarshaller does not support unmarshalling using SAX XMLReaders");
357 }
358 }