Skip to content

Commit d4b0ae9

Browse files
committed
AbstractMarshaller pre-implements getDefaultEncoding() method
Issue: SPR-11635
1 parent 8f28a93 commit d4b0ae9

File tree

2 files changed

+130
-140
lines changed

2 files changed

+130
-140
lines changed

spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java

Lines changed: 113 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import org.apache.commons.logging.Log;
4242
import org.apache.commons.logging.LogFactory;
43+
import org.w3c.dom.Document;
4344
import org.w3c.dom.Node;
4445
import org.xml.sax.ContentHandler;
4546
import org.xml.sax.InputSource;
@@ -66,15 +67,15 @@
6667
*/
6768
public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
6869

69-
/** Logger available to subclasses. */
70+
/** Logger available to subclasses */
7071
protected final Log logger = LogFactory.getLog(getClass());
7172

73+
private boolean processExternalEntities = false;
74+
7275
private DocumentBuilderFactory documentBuilderFactory;
7376

7477
private final Object documentBuilderFactoryMonitor = new Object();
7578

76-
private boolean processExternalEntities = false;
77-
7879

7980
/**
8081
* Indicates whether external XML entities are processed when unmarshalling.
@@ -89,83 +90,48 @@ public void setProcessExternalEntities(boolean processExternalEntities) {
8990
}
9091

9192
/**
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()
9395
*/
9496
public boolean isProcessExternalEntities() {
9597
return this.processExternalEntities;
9698
}
9799

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-
104100

105101
/**
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)
118105
*/
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();
132115
}
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);
135119
}
136120
}
137121

138122
/**
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
151129
*/
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;
169135
}
170136

171137
/**
@@ -182,21 +148,6 @@ protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
182148
return factory.newDocumentBuilder();
183149
}
184150

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-
200151
/**
201152
* Create an {@code XMLReader} that this marshaller will when passed an empty {@code SAXSource}.
202153
* @return the XMLReader
@@ -208,9 +159,50 @@ protected XMLReader createXmlReader() throws SAXException {
208159
return xmlReader;
209160
}
210161

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+
211170

212171
// Marshalling
213172

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+
214206
/**
215207
* Template method for handling {@code DOMResult}s.
216208
* <p>This implementation delegates to {@code marshalDomNode}.
@@ -222,19 +214,7 @@ protected XMLReader createXmlReader() throws SAXException {
222214
*/
223215
protected void marshalDomResult(Object graph, DOMResult domResult) throws XmlMappingException {
224216
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());
238218
}
239219
marshalDomNode(graph, domResult.getNode());
240220
}
@@ -309,6 +289,39 @@ else if (streamResult.getWriter() != null) {
309289

310290
// Unmarshalling
311291

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+
312325
/**
313326
* Template method for handling {@code DOMSource}s.
314327
* <p>This implementation delegates to {@code unmarshalDomNode}.
@@ -322,19 +335,7 @@ else if (streamResult.getWriter() != null) {
322335
*/
323336
protected Object unmarshalDomSource(DOMSource domSource) throws XmlMappingException {
324337
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());
338339
}
339340
return unmarshalDomNode(domSource.getNode());
340341
}
@@ -391,18 +392,17 @@ protected Object unmarshalSaxSource(SAXSource saxSource) throws XmlMappingExcept
391392
* Template method for handling {@code StreamSource}s with protection against
392393
* the XML External Entity (XXE) processing vulnerability taking into account
393394
* 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
396396
* to {@link #unmarshalSaxSource(javax.xml.transform.sax.SAXSource)}.
397-
*
398397
* @param streamSource the {@code StreamSource}
399398
* @return the object graph
400399
* @throws IOException if an I/O exception occurs
401400
* @throws XmlMappingException if the given source cannot be mapped to an object
402-
*
403401
* @see <a href="https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing">XML_External_Entity_(XXE)_Processing</a>
404402
*/
405-
protected Object unmarshalStreamSourceNoExternalEntitities(StreamSource streamSource) throws XmlMappingException, IOException {
403+
protected Object unmarshalStreamSourceNoExternalEntitities(StreamSource streamSource)
404+
throws XmlMappingException, IOException {
405+
406406
InputSource inputSource;
407407
if (streamSource.getInputStream() != null) {
408408
inputSource = new InputSource(streamSource.getInputStream());
@@ -420,10 +420,9 @@ else if (streamSource.getReader() != null) {
420420
/**
421421
* Template method for handling {@code StreamSource}s.
422422
* <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
424424
* {@link #unmarshal(javax.xml.transform.Source)}. The method invoked instead is
425425
* {@link #unmarshalStreamSourceNoExternalEntitities(javax.xml.transform.stream.StreamSource)}.
426-
*
427426
* @param streamSource the {@code StreamSource}
428427
* @return the object graph
429428
* @throws IOException if an I/O exception occurs
@@ -507,7 +506,6 @@ protected abstract void marshalOutputStream(Object graph, OutputStream outputStr
507506
protected abstract void marshalWriter(Object graph, Writer writer)
508507
throws XmlMappingException, IOException;
509508

510-
511509
/**
512510
* Abstract template method for unmarshalling from a given DOM {@code Node}.
513511
* @param node the DOM node that contains the objects to be unmarshalled

0 commit comments

Comments
 (0)