1 package com.fasterxml.jackson.dataformat.xml.ser;
2
3 import java.io.IOException;
4
5 import javax.xml.namespace.QName;
6 import javax.xml.stream.XMLStreamException;
7
8 import com.fasterxml.jackson.core.*;
9 import com.fasterxml.jackson.databind.JavaType;
10 import com.fasterxml.jackson.databind.JsonMappingException;
11 import com.fasterxml.jackson.databind.JsonSerializer;
12 import com.fasterxml.jackson.databind.PropertyName;
13 import com.fasterxml.jackson.databind.SerializationConfig;
14 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
15 import com.fasterxml.jackson.databind.ser.SerializerFactory;
16 import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
17 import com.fasterxml.jackson.databind.util.TokenBuffer;
18 import com.fasterxml.jackson.dataformat.xml.util.StaxUtil;
19 import com.fasterxml.jackson.dataformat.xml.util.TypeUtil;
20 import com.fasterxml.jackson.dataformat.xml.util.XmlRootNameLookup;
21
22
27 public class XmlSerializerProvider extends DefaultSerializerProvider
28 {
29
30 private static final long serialVersionUID = 1L;
31
32
36 protected final static QName ROOT_NAME_FOR_NULL = new QName("null");
37
38 protected final XmlRootNameLookup _rootNameLookup;
39
40 public XmlSerializerProvider(XmlRootNameLookup rootNames)
41 {
42 super();
43 _rootNameLookup = rootNames;
44 }
45
46 public XmlSerializerProvider(XmlSerializerProvider src,
47 SerializationConfig config, SerializerFactory f)
48 {
49 super(src, config, f);
50 _rootNameLookup = src._rootNameLookup;
51 }
52
53
56 protected XmlSerializerProvider(XmlSerializerProvider src) {
57 super(src);
58
59
60 _rootNameLookup = new XmlRootNameLookup();
61 }
62
63
68
69 @Override
70 public DefaultSerializerProvider copy() {
71 return new XmlSerializerProvider(this);
72 }
73
74 @Override
75 public DefaultSerializerProvider createInstance(SerializationConfig config,
76 SerializerFactory jsf) {
77 return new XmlSerializerProvider(this, config, jsf);
78 }
79
80 @SuppressWarnings("resource")
81 @Override
82 public void serializeValue(JsonGenerator gen, Object value) throws IOException
83 {
84 _generator = gen;
85 if (value == null) {
86 _serializeXmlNull(gen);
87 return;
88 }
89 final Class<?> cls = value.getClass();
90 final boolean asArray;
91 final ToXmlGenerator xgen = _asXmlGenerator(gen);
92 if (xgen == null) {
93 asArray = false;
94 } else {
95 QName rootName = _rootNameFromConfig();
96 if (rootName == null) {
97 rootName = _rootNameLookup.findRootName(cls, _config);
98 }
99 _initWithRootName(xgen, rootName);
100 asArray = TypeUtil.isIndexedType(cls);
101 if (asArray) {
102 _startRootArray(xgen, rootName);
103 }
104 }
105
106
107 final JsonSerializer<Object> ser = findTypedValueSerializer(cls, true, null);
108 try {
109 ser.serialize(value, gen, this);
110 } catch (Exception e) {
111 throw _wrapAsIOE(gen, e);
112 }
113
114
115 if (asArray) {
116 gen.writeEndObject();
117 }
118 }
119
120 @Override
121 public void serializeValue(JsonGenerator gen, Object value, JavaType rootType) throws IOException
122 {
123 serializeValue(gen, value, rootType, null);
124 }
125
126
127 @SuppressWarnings("resource")
128 @Override
129 public void serializeValue(JsonGenerator gen, Object value, JavaType rootType,
130 JsonSerializer<Object> ser) throws IOException
131 {
132 _generator = gen;
133 if (value == null) {
134 _serializeXmlNull(gen);
135 return;
136 }
137
138 if ((rootType != null) && !rootType.getRawClass().isAssignableFrom(value.getClass())) {
139 _reportIncompatibleRootType(value, rootType);
140 }
141 final boolean asArray;
142 final ToXmlGenerator xgen = _asXmlGenerator(gen);
143 if (xgen == null) {
144 asArray = false;
145 } else {
146 QName rootName = _rootNameFromConfig();
147 if (rootName == null) {
148 rootName = _rootNameLookup.findRootName(rootType, _config);
149 }
150 _initWithRootName(xgen, rootName);
151 asArray = TypeUtil.isIndexedType(rootType);
152 if (asArray) {
153 _startRootArray(xgen, rootName);
154 }
155 }
156 if (ser == null) {
157 ser = findTypedValueSerializer(rootType, true, null);
158 }
159
160 try {
161 ser.serialize(value, gen, this);
162 } catch (Exception e) {
163 throw _wrapAsIOE(gen, e);
164 }
165
166 if (asArray) {
167 gen.writeEndObject();
168 }
169 }
170
171 @SuppressWarnings("resource")
172 @Override
173 public void serializePolymorphic(JsonGenerator gen, Object value, JavaType rootType,
174 JsonSerializer<Object> valueSer, TypeSerializer typeSer)
175 throws IOException
176 {
177 _generator = gen;
178 if (value == null) {
179 _serializeXmlNull(gen);
180 return;
181 }
182
183 if ((rootType != null) && !rootType.getRawClass().isAssignableFrom(value.getClass())) {
184 _reportIncompatibleRootType(value, rootType);
185 }
186 final boolean asArray;
187 final ToXmlGenerator xgen = _asXmlGenerator(gen);
188 if (xgen == null) {
189 asArray = false;
190 } else {
191 QName rootName = _rootNameFromConfig();
192 if (rootName == null) {
193 rootName = _rootNameLookup.findRootName(rootType, _config);
194 }
195 _initWithRootName(xgen, rootName);
196 asArray = TypeUtil.isIndexedType(rootType);
197 if (asArray) {
198 _startRootArray(xgen, rootName);
199 }
200 }
201
202 if (valueSer == null) {
203 if ((rootType != null) && rootType.isContainerType()) {
204 valueSer = findValueSerializer(rootType, null);
205 } else {
206 valueSer = findValueSerializer(value.getClass(), null);
207 }
208 }
209
210 try {
211 valueSer.serializeWithType(value, gen, this, typeSer);
212 } catch (Exception e) {
213 throw _wrapAsIOE(gen, e);
214 }
215
216 if (asArray) {
217 gen.writeEndObject();
218 }
219 }
220
221 protected void _serializeXmlNull(JsonGenerator jgen) throws IOException
222 {
223
224
225 QName rootName = _rootNameFromConfig();
226 if (rootName == null) {
227 rootName = ROOT_NAME_FOR_NULL;
228 }
229 if (jgen instanceof ToXmlGenerator) {
230 _initWithRootName((ToXmlGenerator) jgen, rootName);
231 }
232 super.serializeValue(jgen, null);
233 }
234
235 protected void _startRootArray(ToXmlGenerator xgen, QName rootName) throws IOException
236 {
237 xgen.writeStartObject();
238
239 xgen.writeFieldName("item");
240 }
241
242 protected void _initWithRootName(ToXmlGenerator xgen, QName rootName) throws IOException
243 {
244
248 if (!xgen.setNextNameIfMissing(rootName)) {
249
250 if (xgen.inRoot()) {
251 xgen.setNextName(rootName);
252 }
253 }
254 xgen.initGenerator();
255 String ns = rootName.getNamespaceURI();
256
260 if (ns != null && ns.length() > 0) {
261 try {
262 xgen.getStaxWriter().setDefaultNamespace(ns);
263 } catch (XMLStreamException e) {
264 StaxUtil.throwAsGenerationException(e, xgen);
265 }
266 }
267 }
268
269 protected QName _rootNameFromConfig()
270 {
271 PropertyName name = _config.getFullRootName();
272 if (name == null) {
273 return null;
274 }
275 String ns = name.getNamespace();
276 if (ns == null || ns.isEmpty()) {
277 return new QName(name.getSimpleName());
278 }
279 return new QName(ns, name.getSimpleName());
280 }
281
282 protected ToXmlGenerator _asXmlGenerator(JsonGenerator gen)
283 throws JsonMappingException
284 {
285
286 if (!(gen instanceof ToXmlGenerator)) {
287
288 if (!(gen instanceof TokenBuffer)) {
289 throw JsonMappingException.from(gen,
290 "XmlMapper does not with generators of type other than ToXmlGenerator; got: "+gen.getClass().getName());
291 }
292 return null;
293 }
294 return (ToXmlGenerator) gen;
295 }
296
297 protected IOException _wrapAsIOE(JsonGenerator g, Exception e) {
298 if (e instanceof IOException) {
299 return (IOException) e;
300 }
301 String msg = e.getMessage();
302 if (msg == null) {
303 msg = "[no message for "+e.getClass().getName()+"]";
304 }
305 return new JsonMappingException(g, msg, e);
306 }
307 }
308