40
40
41
41
import org .apache .commons .logging .Log ;
42
42
import org .apache .commons .logging .LogFactory ;
43
+ import org .w3c .dom .Document ;
43
44
import org .w3c .dom .Node ;
44
45
import org .xml .sax .ContentHandler ;
45
46
import org .xml .sax .InputSource ;
66
67
*/
67
68
public abstract class AbstractMarshaller implements Marshaller , Unmarshaller {
68
69
69
- /** Logger available to subclasses. */
70
+ /** Logger available to subclasses */
70
71
protected final Log logger = LogFactory .getLog (getClass ());
71
72
73
+ private boolean processExternalEntities = false ;
74
+
72
75
private DocumentBuilderFactory documentBuilderFactory ;
73
76
74
77
private final Object documentBuilderFactoryMonitor = new Object ();
75
78
76
- private boolean processExternalEntities = false ;
77
-
78
79
79
80
/**
80
81
* Indicates whether external XML entities are processed when unmarshalling.
@@ -89,83 +90,48 @@ public void setProcessExternalEntities(boolean processExternalEntities) {
89
90
}
90
91
91
92
/**
92
- * @return the configured value for whether XML external entities are allowed.
93
+ * Returns the configured value for whether XML external entities are allowed.
94
+ * @see #createXmlReader()
93
95
*/
94
96
public boolean isProcessExternalEntities () {
95
97
return this .processExternalEntities ;
96
98
}
97
99
98
- /**
99
- * @return the default encoding to use for marshalling or unmarshalling from
100
- * a byte stream, or {@code null}.
101
- */
102
- abstract protected String getDefaultEncoding ();
103
-
104
100
105
101
/**
106
- * Marshals the object graph with the given root into the provided {@code javax.xml.transform.Result}.
107
- * <p>This implementation inspects the given result, and calls {@code marshalDomResult},
108
- * {@code marshalSaxResult}, or {@code marshalStreamResult}.
109
- * @param graph the root of the object graph to marshal
110
- * @param result the result to marshal to
111
- * @throws IOException if an I/O exception occurs
112
- * @throws XmlMappingException if the given object cannot be marshalled to the result
113
- * @throws IllegalArgumentException if {@code result} if neither a {@code DOMResult},
114
- * a {@code SAXResult}, nor a {@code StreamResult}
115
- * @see #marshalDomResult(Object, javax.xml.transform.dom.DOMResult)
116
- * @see #marshalSaxResult(Object, javax.xml.transform.sax.SAXResult)
117
- * @see #marshalStreamResult(Object, javax.xml.transform.stream.StreamResult)
102
+ * Build a new {@link Document} from this marshaller's {@link DocumentBuilderFactory}.
103
+ * @see #createDocumentBuilderFactory()
104
+ * @see #createDocumentBuilder(DocumentBuilderFactory)
118
105
*/
119
- @ Override
120
- public final void marshal (Object graph , Result result ) throws IOException , XmlMappingException {
121
- if (result instanceof DOMResult ) {
122
- marshalDomResult (graph , (DOMResult ) result );
123
- }
124
- else if (StaxUtils .isStaxResult (result )) {
125
- marshalStaxResult (graph , result );
126
- }
127
- else if (result instanceof SAXResult ) {
128
- marshalSaxResult (graph , (SAXResult ) result );
129
- }
130
- else if (result instanceof StreamResult ) {
131
- marshalStreamResult (graph , (StreamResult ) result );
106
+ protected Document buildDocument () {
107
+ try {
108
+ synchronized (this .documentBuilderFactoryMonitor ) {
109
+ if (this .documentBuilderFactory == null ) {
110
+ this .documentBuilderFactory = createDocumentBuilderFactory ();
111
+ }
112
+ }
113
+ DocumentBuilder documentBuilder = createDocumentBuilder (this .documentBuilderFactory );
114
+ return documentBuilder .newDocument ();
132
115
}
133
- else {
134
- throw new IllegalArgumentException ("Unknown Result type: " + result .getClass ());
116
+ catch (ParserConfigurationException ex ) {
117
+ throw new UnmarshallingFailureException (
118
+ "Could not create document placeholder for DOMSource: " + ex .getMessage (), ex );
135
119
}
136
120
}
137
121
138
122
/**
139
- * Unmarshals the given provided {@code javax.xml.transform.Source} into an object graph.
140
- * <p>This implementation inspects the given result, and calls {@code unmarshalDomSource},
141
- * {@code unmarshalSaxSource}, or {@code unmarshalStreamSource}.
142
- * @param source the source to marshal from
143
- * @return the object graph
144
- * @throws IOException if an I/O Exception occurs
145
- * @throws XmlMappingException if the given source cannot be mapped to an object
146
- * @throws IllegalArgumentException if {@code source} is neither a {@code DOMSource},
147
- * a {@code SAXSource}, nor a {@code StreamSource}
148
- * @see #unmarshalDomSource(javax.xml.transform.dom.DOMSource)
149
- * @see #unmarshalSaxSource(javax.xml.transform.sax.SAXSource)
150
- * @see #unmarshalStreamSource(javax.xml.transform.stream.StreamSource)
123
+ * Create a {@code DocumentBuilder} that this marshaller will use for creating
124
+ * DOM documents when passed an empty {@code DOMSource}.
125
+ * <p>The resulting {@code DocumentBuilderFactory} is cached, so this method
126
+ * will only be called once.
127
+ * @return the DocumentBuilderFactory
128
+ * @throws ParserConfigurationException if thrown by JAXP methods
151
129
*/
152
- @ Override
153
- public final Object unmarshal (Source source ) throws IOException , XmlMappingException {
154
- if (source instanceof DOMSource ) {
155
- return unmarshalDomSource ((DOMSource ) source );
156
- }
157
- else if (StaxUtils .isStaxSource (source )) {
158
- return unmarshalStaxSource (source );
159
- }
160
- else if (source instanceof SAXSource ) {
161
- return unmarshalSaxSource ((SAXSource ) source );
162
- }
163
- else if (source instanceof StreamSource ) {
164
- return unmarshalStreamSourceNoExternalEntitities ((StreamSource ) source );
165
- }
166
- else {
167
- throw new IllegalArgumentException ("Unknown Source type: " + source .getClass ());
168
- }
130
+ protected DocumentBuilderFactory createDocumentBuilderFactory () throws ParserConfigurationException {
131
+ DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance ();
132
+ factory .setValidating (false );
133
+ factory .setNamespaceAware (true );
134
+ return factory ;
169
135
}
170
136
171
137
/**
@@ -182,21 +148,6 @@ protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
182
148
return factory .newDocumentBuilder ();
183
149
}
184
150
185
- /**
186
- * Create a {@code DocumentBuilder} that this marshaller will use for creating
187
- * DOM documents when passed an empty {@code DOMSource}.
188
- * <p>The resulting {@code DocumentBuilderFactory} is cached, so this method
189
- * will only be called once.
190
- * @return the DocumentBuilderFactory
191
- * @throws ParserConfigurationException if thrown by JAXP methods
192
- */
193
- protected DocumentBuilderFactory createDocumentBuilderFactory () throws ParserConfigurationException {
194
- DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance ();
195
- factory .setValidating (false );
196
- factory .setNamespaceAware (true );
197
- return factory ;
198
- }
199
-
200
151
/**
201
152
* Create an {@code XMLReader} that this marshaller will when passed an empty {@code SAXSource}.
202
153
* @return the XMLReader
@@ -208,9 +159,50 @@ protected XMLReader createXmlReader() throws SAXException {
208
159
return xmlReader ;
209
160
}
210
161
162
+ /**
163
+ * Determine the default encoding to use for marshalling or unmarshalling from
164
+ * a byte stream, or {@code null} if none.
165
+ */
166
+ protected String getDefaultEncoding () {
167
+ return null ;
168
+ }
169
+
211
170
212
171
// Marshalling
213
172
173
+ /**
174
+ * Marshals the object graph with the given root into the provided {@code javax.xml.transform.Result}.
175
+ * <p>This implementation inspects the given result, and calls {@code marshalDomResult},
176
+ * {@code marshalSaxResult}, or {@code marshalStreamResult}.
177
+ * @param graph the root of the object graph to marshal
178
+ * @param result the result to marshal to
179
+ * @throws IOException if an I/O exception occurs
180
+ * @throws XmlMappingException if the given object cannot be marshalled to the result
181
+ * @throws IllegalArgumentException if {@code result} if neither a {@code DOMResult},
182
+ * a {@code SAXResult}, nor a {@code StreamResult}
183
+ * @see #marshalDomResult(Object, javax.xml.transform.dom.DOMResult)
184
+ * @see #marshalSaxResult(Object, javax.xml.transform.sax.SAXResult)
185
+ * @see #marshalStreamResult(Object, javax.xml.transform.stream.StreamResult)
186
+ */
187
+ @ Override
188
+ public final void marshal (Object graph , Result result ) throws IOException , XmlMappingException {
189
+ if (result instanceof DOMResult ) {
190
+ marshalDomResult (graph , (DOMResult ) result );
191
+ }
192
+ else if (StaxUtils .isStaxResult (result )) {
193
+ marshalStaxResult (graph , result );
194
+ }
195
+ else if (result instanceof SAXResult ) {
196
+ marshalSaxResult (graph , (SAXResult ) result );
197
+ }
198
+ else if (result instanceof StreamResult ) {
199
+ marshalStreamResult (graph , (StreamResult ) result );
200
+ }
201
+ else {
202
+ throw new IllegalArgumentException ("Unknown Result type: " + result .getClass ());
203
+ }
204
+ }
205
+
214
206
/**
215
207
* Template method for handling {@code DOMResult}s.
216
208
* <p>This implementation delegates to {@code marshalDomNode}.
@@ -222,19 +214,7 @@ protected XMLReader createXmlReader() throws SAXException {
222
214
*/
223
215
protected void marshalDomResult (Object graph , DOMResult domResult ) throws XmlMappingException {
224
216
if (domResult .getNode () == null ) {
225
- try {
226
- synchronized (this .documentBuilderFactoryMonitor ) {
227
- if (this .documentBuilderFactory == null ) {
228
- this .documentBuilderFactory = createDocumentBuilderFactory ();
229
- }
230
- }
231
- DocumentBuilder documentBuilder = createDocumentBuilder (this .documentBuilderFactory );
232
- domResult .setNode (documentBuilder .newDocument ());
233
- }
234
- catch (ParserConfigurationException ex ) {
235
- throw new UnmarshallingFailureException (
236
- "Could not create document placeholder for DOMResult: " + ex .getMessage (), ex );
237
- }
217
+ domResult .setNode (buildDocument ());
238
218
}
239
219
marshalDomNode (graph , domResult .getNode ());
240
220
}
@@ -309,6 +289,39 @@ else if (streamResult.getWriter() != null) {
309
289
310
290
// Unmarshalling
311
291
292
+ /**
293
+ * Unmarshals the given provided {@code javax.xml.transform.Source} into an object graph.
294
+ * <p>This implementation inspects the given result, and calls {@code unmarshalDomSource},
295
+ * {@code unmarshalSaxSource}, or {@code unmarshalStreamSource}.
296
+ * @param source the source to marshal from
297
+ * @return the object graph
298
+ * @throws IOException if an I/O Exception occurs
299
+ * @throws XmlMappingException if the given source cannot be mapped to an object
300
+ * @throws IllegalArgumentException if {@code source} is neither a {@code DOMSource},
301
+ * a {@code SAXSource}, nor a {@code StreamSource}
302
+ * @see #unmarshalDomSource(javax.xml.transform.dom.DOMSource)
303
+ * @see #unmarshalSaxSource(javax.xml.transform.sax.SAXSource)
304
+ * @see #unmarshalStreamSource(javax.xml.transform.stream.StreamSource)
305
+ */
306
+ @ Override
307
+ public final Object unmarshal (Source source ) throws IOException , XmlMappingException {
308
+ if (source instanceof DOMSource ) {
309
+ return unmarshalDomSource ((DOMSource ) source );
310
+ }
311
+ else if (StaxUtils .isStaxSource (source )) {
312
+ return unmarshalStaxSource (source );
313
+ }
314
+ else if (source instanceof SAXSource ) {
315
+ return unmarshalSaxSource ((SAXSource ) source );
316
+ }
317
+ else if (source instanceof StreamSource ) {
318
+ return unmarshalStreamSourceNoExternalEntitities ((StreamSource ) source );
319
+ }
320
+ else {
321
+ throw new IllegalArgumentException ("Unknown Source type: " + source .getClass ());
322
+ }
323
+ }
324
+
312
325
/**
313
326
* Template method for handling {@code DOMSource}s.
314
327
* <p>This implementation delegates to {@code unmarshalDomNode}.
@@ -322,19 +335,7 @@ else if (streamResult.getWriter() != null) {
322
335
*/
323
336
protected Object unmarshalDomSource (DOMSource domSource ) throws XmlMappingException {
324
337
if (domSource .getNode () == null ) {
325
- try {
326
- synchronized (this .documentBuilderFactoryMonitor ) {
327
- if (this .documentBuilderFactory == null ) {
328
- this .documentBuilderFactory = createDocumentBuilderFactory ();
329
- }
330
- }
331
- DocumentBuilder documentBuilder = createDocumentBuilder (this .documentBuilderFactory );
332
- domSource .setNode (documentBuilder .newDocument ());
333
- }
334
- catch (ParserConfigurationException ex ) {
335
- throw new UnmarshallingFailureException (
336
- "Could not create document placeholder for DOMSource: " + ex .getMessage (), ex );
337
- }
338
+ domSource .setNode (buildDocument ());
338
339
}
339
340
return unmarshalDomNode (domSource .getNode ());
340
341
}
@@ -391,18 +392,17 @@ protected Object unmarshalSaxSource(SAXSource saxSource) throws XmlMappingExcept
391
392
* Template method for handling {@code StreamSource}s with protection against
392
393
* the XML External Entity (XXE) processing vulnerability taking into account
393
394
* the value of the {@link #setProcessExternalEntities(boolean)} property.
394
- * <p>
395
- * The default implementation wraps the StreamSource as a SAXSource and delegates
395
+ * <p>The default implementation wraps the StreamSource as a SAXSource and delegates
396
396
* to {@link #unmarshalSaxSource(javax.xml.transform.sax.SAXSource)}.
397
- *
398
397
* @param streamSource the {@code StreamSource}
399
398
* @return the object graph
400
399
* @throws IOException if an I/O exception occurs
401
400
* @throws XmlMappingException if the given source cannot be mapped to an object
402
- *
403
401
* @see <a href="https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing">XML_External_Entity_(XXE)_Processing</a>
404
402
*/
405
- protected Object unmarshalStreamSourceNoExternalEntitities (StreamSource streamSource ) throws XmlMappingException , IOException {
403
+ protected Object unmarshalStreamSourceNoExternalEntitities (StreamSource streamSource )
404
+ throws XmlMappingException , IOException {
405
+
406
406
InputSource inputSource ;
407
407
if (streamSource .getInputStream () != null ) {
408
408
inputSource = new InputSource (streamSource .getInputStream ());
@@ -420,10 +420,9 @@ else if (streamSource.getReader() != null) {
420
420
/**
421
421
* Template method for handling {@code StreamSource}s.
422
422
* <p>This implementation defers to {@code unmarshalInputStream} or {@code unmarshalReader}.
423
- * <p>As of 3.2.8 and 4.0.2 this method is no longer invoked from
423
+ * <p>As of Spring 3.2.8, this method is no longer invoked from
424
424
* {@link #unmarshal(javax.xml.transform.Source)}. The method invoked instead is
425
425
* {@link #unmarshalStreamSourceNoExternalEntitities(javax.xml.transform.stream.StreamSource)}.
426
- *
427
426
* @param streamSource the {@code StreamSource}
428
427
* @return the object graph
429
428
* @throws IOException if an I/O exception occurs
@@ -507,7 +506,6 @@ protected abstract void marshalOutputStream(Object graph, OutputStream outputStr
507
506
protected abstract void marshalWriter (Object graph , Writer writer )
508
507
throws XmlMappingException , IOException ;
509
508
510
-
511
509
/**
512
510
* Abstract template method for unmarshalling from a given DOM {@code Node}.
513
511
* @param node the DOM node that contains the objects to be unmarshalled
0 commit comments