diff --git a/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java index 2df808e5746..b3ef14bab9a 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java @@ -40,6 +40,7 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; @@ -66,15 +67,15 @@ import org.springframework.util.xml.StaxUtils; */ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { - /** Logger available to subclasses. */ + /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + private boolean processExternalEntities = false; + private DocumentBuilderFactory documentBuilderFactory; private final Object documentBuilderFactoryMonitor = new Object(); - private boolean processExternalEntities = false; - /** * Indicates whether external XML entities are processed when unmarshalling. @@ -89,83 +90,48 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { } /** - * @return the configured value for whether XML external entities are allowed. + * Returns the configured value for whether XML external entities are allowed. + * @see #createXmlReader() */ public boolean isProcessExternalEntities() { return this.processExternalEntities; } - /** - * @return the default encoding to use for marshalling or unmarshalling from - * a byte stream, or {@code null}. - */ - abstract protected String getDefaultEncoding(); - /** - * Marshals the object graph with the given root into the provided {@code javax.xml.transform.Result}. - *
This implementation inspects the given result, and calls {@code marshalDomResult}, - * {@code marshalSaxResult}, or {@code marshalStreamResult}. - * @param graph the root of the object graph to marshal - * @param result the result to marshal to - * @throws IOException if an I/O exception occurs - * @throws XmlMappingException if the given object cannot be marshalled to the result - * @throws IllegalArgumentException if {@code result} if neither a {@code DOMResult}, - * a {@code SAXResult}, nor a {@code StreamResult} - * @see #marshalDomResult(Object, javax.xml.transform.dom.DOMResult) - * @see #marshalSaxResult(Object, javax.xml.transform.sax.SAXResult) - * @see #marshalStreamResult(Object, javax.xml.transform.stream.StreamResult) + * Build a new {@link Document} from this marshaller's {@link DocumentBuilderFactory}. + * @see #createDocumentBuilderFactory() + * @see #createDocumentBuilder(DocumentBuilderFactory) */ - @Override - public final void marshal(Object graph, Result result) throws IOException, XmlMappingException { - if (result instanceof DOMResult) { - marshalDomResult(graph, (DOMResult) result); - } - else if (StaxUtils.isStaxResult(result)) { - marshalStaxResult(graph, result); - } - else if (result instanceof SAXResult) { - marshalSaxResult(graph, (SAXResult) result); - } - else if (result instanceof StreamResult) { - marshalStreamResult(graph, (StreamResult) result); + protected Document buildDocument() { + try { + synchronized (this.documentBuilderFactoryMonitor) { + if (this.documentBuilderFactory == null) { + this.documentBuilderFactory = createDocumentBuilderFactory(); + } + } + DocumentBuilder documentBuilder = createDocumentBuilder(this.documentBuilderFactory); + return documentBuilder.newDocument(); } - else { - throw new IllegalArgumentException("Unknown Result type: " + result.getClass()); + catch (ParserConfigurationException ex) { + throw new UnmarshallingFailureException( + "Could not create document placeholder for DOMSource: " + ex.getMessage(), ex); } } /** - * Unmarshals the given provided {@code javax.xml.transform.Source} into an object graph. - *
This implementation inspects the given result, and calls {@code unmarshalDomSource}, - * {@code unmarshalSaxSource}, or {@code unmarshalStreamSource}. - * @param source the source to marshal from - * @return the object graph - * @throws IOException if an I/O Exception occurs - * @throws XmlMappingException if the given source cannot be mapped to an object - * @throws IllegalArgumentException if {@code source} is neither a {@code DOMSource}, - * a {@code SAXSource}, nor a {@code StreamSource} - * @see #unmarshalDomSource(javax.xml.transform.dom.DOMSource) - * @see #unmarshalSaxSource(javax.xml.transform.sax.SAXSource) - * @see #unmarshalStreamSource(javax.xml.transform.stream.StreamSource) + * Create a {@code DocumentBuilder} that this marshaller will use for creating + * DOM documents when passed an empty {@code DOMSource}. + *
The resulting {@code DocumentBuilderFactory} is cached, so this method + * will only be called once. + * @return the DocumentBuilderFactory + * @throws ParserConfigurationException if thrown by JAXP methods */ - @Override - public final Object unmarshal(Source source) throws IOException, XmlMappingException { - if (source instanceof DOMSource) { - return unmarshalDomSource((DOMSource) source); - } - else if (StaxUtils.isStaxSource(source)) { - return unmarshalStaxSource(source); - } - else if (source instanceof SAXSource) { - return unmarshalSaxSource((SAXSource) source); - } - else if (source instanceof StreamSource) { - return unmarshalStreamSourceNoExternalEntitities((StreamSource) source); - } - else { - throw new IllegalArgumentException("Unknown Source type: " + source.getClass()); - } + protected DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setValidating(false); + factory.setNamespaceAware(true); + return factory; } /** @@ -182,21 +148,6 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { return factory.newDocumentBuilder(); } - /** - * Create a {@code DocumentBuilder} that this marshaller will use for creating - * DOM documents when passed an empty {@code DOMSource}. - *
The resulting {@code DocumentBuilderFactory} is cached, so this method - * will only be called once. - * @return the DocumentBuilderFactory - * @throws ParserConfigurationException if thrown by JAXP methods - */ - protected DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(false); - factory.setNamespaceAware(true); - return factory; - } - /** * Create an {@code XMLReader} that this marshaller will when passed an empty {@code SAXSource}. * @return the XMLReader @@ -208,9 +159,50 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { return xmlReader; } + /** + * Determine the default encoding to use for marshalling or unmarshalling from + * a byte stream, or {@code null} if none. + */ + protected String getDefaultEncoding() { + return null; + } + // Marshalling + /** + * Marshals the object graph with the given root into the provided {@code javax.xml.transform.Result}. + *
This implementation inspects the given result, and calls {@code marshalDomResult}, + * {@code marshalSaxResult}, or {@code marshalStreamResult}. + * @param graph the root of the object graph to marshal + * @param result the result to marshal to + * @throws IOException if an I/O exception occurs + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IllegalArgumentException if {@code result} if neither a {@code DOMResult}, + * a {@code SAXResult}, nor a {@code StreamResult} + * @see #marshalDomResult(Object, javax.xml.transform.dom.DOMResult) + * @see #marshalSaxResult(Object, javax.xml.transform.sax.SAXResult) + * @see #marshalStreamResult(Object, javax.xml.transform.stream.StreamResult) + */ + @Override + public final void marshal(Object graph, Result result) throws IOException, XmlMappingException { + if (result instanceof DOMResult) { + marshalDomResult(graph, (DOMResult) result); + } + else if (StaxUtils.isStaxResult(result)) { + marshalStaxResult(graph, result); + } + else if (result instanceof SAXResult) { + marshalSaxResult(graph, (SAXResult) result); + } + else if (result instanceof StreamResult) { + marshalStreamResult(graph, (StreamResult) result); + } + else { + throw new IllegalArgumentException("Unknown Result type: " + result.getClass()); + } + } + /** * Template method for handling {@code DOMResult}s. *
This implementation delegates to {@code marshalDomNode}. @@ -222,19 +214,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { */ protected void marshalDomResult(Object graph, DOMResult domResult) throws XmlMappingException { if (domResult.getNode() == null) { - try { - synchronized (this.documentBuilderFactoryMonitor) { - if (this.documentBuilderFactory == null) { - this.documentBuilderFactory = createDocumentBuilderFactory(); - } - } - DocumentBuilder documentBuilder = createDocumentBuilder(this.documentBuilderFactory); - domResult.setNode(documentBuilder.newDocument()); - } - catch (ParserConfigurationException ex) { - throw new UnmarshallingFailureException( - "Could not create document placeholder for DOMResult: " + ex.getMessage(), ex); - } + domResult.setNode(buildDocument()); } marshalDomNode(graph, domResult.getNode()); } @@ -309,6 +289,39 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { // Unmarshalling + /** + * Unmarshals the given provided {@code javax.xml.transform.Source} into an object graph. + *
This implementation inspects the given result, and calls {@code unmarshalDomSource}, + * {@code unmarshalSaxSource}, or {@code unmarshalStreamSource}. + * @param source the source to marshal from + * @return the object graph + * @throws IOException if an I/O Exception occurs + * @throws XmlMappingException if the given source cannot be mapped to an object + * @throws IllegalArgumentException if {@code source} is neither a {@code DOMSource}, + * a {@code SAXSource}, nor a {@code StreamSource} + * @see #unmarshalDomSource(javax.xml.transform.dom.DOMSource) + * @see #unmarshalSaxSource(javax.xml.transform.sax.SAXSource) + * @see #unmarshalStreamSource(javax.xml.transform.stream.StreamSource) + */ + @Override + public final Object unmarshal(Source source) throws IOException, XmlMappingException { + if (source instanceof DOMSource) { + return unmarshalDomSource((DOMSource) source); + } + else if (StaxUtils.isStaxSource(source)) { + return unmarshalStaxSource(source); + } + else if (source instanceof SAXSource) { + return unmarshalSaxSource((SAXSource) source); + } + else if (source instanceof StreamSource) { + return unmarshalStreamSourceNoExternalEntitities((StreamSource) source); + } + else { + throw new IllegalArgumentException("Unknown Source type: " + source.getClass()); + } + } + /** * Template method for handling {@code DOMSource}s. *
This implementation delegates to {@code unmarshalDomNode}. @@ -322,19 +335,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { */ protected Object unmarshalDomSource(DOMSource domSource) throws XmlMappingException { if (domSource.getNode() == null) { - try { - synchronized (this.documentBuilderFactoryMonitor) { - if (this.documentBuilderFactory == null) { - this.documentBuilderFactory = createDocumentBuilderFactory(); - } - } - DocumentBuilder documentBuilder = createDocumentBuilder(this.documentBuilderFactory); - domSource.setNode(documentBuilder.newDocument()); - } - catch (ParserConfigurationException ex) { - throw new UnmarshallingFailureException( - "Could not create document placeholder for DOMSource: " + ex.getMessage(), ex); - } + domSource.setNode(buildDocument()); } return unmarshalDomNode(domSource.getNode()); } @@ -391,18 +392,17 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { * Template method for handling {@code StreamSource}s with protection against * the XML External Entity (XXE) processing vulnerability taking into account * the value of the {@link #setProcessExternalEntities(boolean)} property. - *
- * The default implementation wraps the StreamSource as a SAXSource and delegates + *
The default implementation wraps the StreamSource as a SAXSource and delegates * to {@link #unmarshalSaxSource(javax.xml.transform.sax.SAXSource)}. - * * @param streamSource the {@code StreamSource} * @return the object graph * @throws IOException if an I/O exception occurs * @throws XmlMappingException if the given source cannot be mapped to an object - * * @see XML_External_Entity_(XXE)_Processing */ - protected Object unmarshalStreamSourceNoExternalEntitities(StreamSource streamSource) throws XmlMappingException, IOException { + protected Object unmarshalStreamSourceNoExternalEntitities(StreamSource streamSource) + throws XmlMappingException, IOException { + InputSource inputSource; if (streamSource.getInputStream() != null) { inputSource = new InputSource(streamSource.getInputStream()); @@ -420,10 +420,9 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { /** * Template method for handling {@code StreamSource}s. *
This implementation defers to {@code unmarshalInputStream} or {@code unmarshalReader}. - *
As of 3.2.8 and 4.0.2 this method is no longer invoked from + *
As of Spring 3.2.8, this method is no longer invoked from
* {@link #unmarshal(javax.xml.transform.Source)}. The method invoked instead is
* {@link #unmarshalStreamSourceNoExternalEntitities(javax.xml.transform.stream.StreamSource)}.
- *
* @param streamSource the {@code StreamSource}
* @return the object graph
* @throws IOException if an I/O exception occurs
@@ -507,7 +506,6 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
protected abstract void marshalWriter(Object graph, Writer writer)
throws XmlMappingException, IOException;
-
/**
* Abstract template method for unmarshalling from a given DOM {@code Node}.
* @param node the DOM node that contains the objects to be unmarshalled
diff --git a/spring-oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java
index 05b9f341136..37b0cb3decb 100644
--- a/spring-oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java
+++ b/spring-oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java
@@ -113,10 +113,6 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
return this.validating;
}
- @Override
- protected String getDefaultEncoding() {
- return null;
- }
/**
* This implementation returns true if the given class is an implementation of {@link XmlObject}.
@@ -327,14 +323,11 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
}
- /**
- * See SPR-7034
- */
private static class NonClosingInputStream extends InputStream {
private final WeakReference