@ -40,6 +40,7 @@ import javax.xml.transform.stream.StreamSource;
@@ -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;
@@ -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 {
@@ -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 } .
* < p > 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 .
* < p > 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 } .
* < p > 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 {
@@ -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 } .
* < p > 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 {
@@ -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 } .
* < p > 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 .
* < p > This implementation delegates to { @code marshalDomNode } .
@ -222,19 +214,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
@@ -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 {
@@ -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 .
* < p > 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 .
* < p > This implementation delegates to { @code unmarshalDomNode } .
@ -322,19 +335,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
@@ -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 {
@@ -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 .
* < p >
* The default implementation wraps the StreamSource as a SAXSource and delegates
* < p > 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 < a href = "https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing" > XML_External_Entity_ ( XXE ) _Processing < / a >
* /
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 {
@@ -420,10 +420,9 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
/ * *
* Template method for handling { @code StreamSource } s .
* < p > This implementation defers to { @code unmarshalInputStream } or { @code unmarshalReader } .
* < p > As of 3 . 2 . 8 and 4 . 0 . 2 this method is no longer invoked from
* < p > 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 {
@@ -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