Browse Source

AbstractMarshaller pre-implements getDefaultEncoding() method

Issue: SPR-11635
pull/512/head
Juergen Hoeller 12 years ago
parent
commit
d4b0ae9787
  1. 228
      spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java
  2. 42
      spring-oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java

228
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.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
@ -66,15 +67,15 @@ import org.springframework.util.xml.StaxUtils;
*/ */
public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
/** Logger available to subclasses. */ /** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass()); protected final Log logger = LogFactory.getLog(getClass());
private boolean processExternalEntities = false;
private DocumentBuilderFactory documentBuilderFactory; private DocumentBuilderFactory documentBuilderFactory;
private final Object documentBuilderFactoryMonitor = new Object(); private final Object documentBuilderFactoryMonitor = new Object();
private boolean processExternalEntities = false;
/** /**
* Indicates whether external XML entities are processed when unmarshalling. * 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() { public boolean isProcessExternalEntities() {
return this.processExternalEntities; 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}. * Build a new {@link Document} from this marshaller's {@link DocumentBuilderFactory}.
* <p>This implementation inspects the given result, and calls {@code marshalDomResult}, * @see #createDocumentBuilderFactory()
* {@code marshalSaxResult}, or {@code marshalStreamResult}. * @see #createDocumentBuilder(DocumentBuilderFactory)
* @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 protected Document buildDocument() {
public final void marshal(Object graph, Result result) throws IOException, XmlMappingException { try {
if (result instanceof DOMResult) { synchronized (this.documentBuilderFactoryMonitor) {
marshalDomResult(graph, (DOMResult) result); if (this.documentBuilderFactory == null) {
} this.documentBuilderFactory = createDocumentBuilderFactory();
else if (StaxUtils.isStaxResult(result)) { }
marshalStaxResult(graph, result); }
} DocumentBuilder documentBuilder = createDocumentBuilder(this.documentBuilderFactory);
else if (result instanceof SAXResult) { return documentBuilder.newDocument();
marshalSaxResult(graph, (SAXResult) result);
}
else if (result instanceof StreamResult) {
marshalStreamResult(graph, (StreamResult) result);
} }
else { catch (ParserConfigurationException ex) {
throw new IllegalArgumentException("Unknown Result type: " + result.getClass()); 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. * Create a {@code DocumentBuilder} that this marshaller will use for creating
* <p>This implementation inspects the given result, and calls {@code unmarshalDomSource}, * DOM documents when passed an empty {@code DOMSource}.
* {@code unmarshalSaxSource}, or {@code unmarshalStreamSource}. * <p>The resulting {@code DocumentBuilderFactory} is cached, so this method
* @param source the source to marshal from * will only be called once.
* @return the object graph * @return the DocumentBuilderFactory
* @throws IOException if an I/O Exception occurs * @throws ParserConfigurationException if thrown by JAXP methods
* @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 protected DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException {
public final Object unmarshal(Source source) throws IOException, XmlMappingException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
if (source instanceof DOMSource) { factory.setValidating(false);
return unmarshalDomSource((DOMSource) source); factory.setNamespaceAware(true);
} return factory;
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());
}
} }
/** /**
@ -182,21 +148,6 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
return factory.newDocumentBuilder(); 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}. * Create an {@code XMLReader} that this marshaller will when passed an empty {@code SAXSource}.
* @return the XMLReader * @return the XMLReader
@ -208,9 +159,50 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
return xmlReader; 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 // 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. * Template method for handling {@code DOMResult}s.
* <p>This implementation delegates to {@code marshalDomNode}. * <p>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 { protected void marshalDomResult(Object graph, DOMResult domResult) throws XmlMappingException {
if (domResult.getNode() == null) { if (domResult.getNode() == null) {
try { domResult.setNode(buildDocument());
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);
}
} }
marshalDomNode(graph, domResult.getNode()); marshalDomNode(graph, domResult.getNode());
} }
@ -309,6 +289,39 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
// Unmarshalling // 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. * Template method for handling {@code DOMSource}s.
* <p>This implementation delegates to {@code unmarshalDomNode}. * <p>This implementation delegates to {@code unmarshalDomNode}.
@ -322,19 +335,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
*/ */
protected Object unmarshalDomSource(DOMSource domSource) throws XmlMappingException { protected Object unmarshalDomSource(DOMSource domSource) throws XmlMappingException {
if (domSource.getNode() == null) { if (domSource.getNode() == null) {
try { domSource.setNode(buildDocument());
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);
}
} }
return unmarshalDomNode(domSource.getNode()); 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 * Template method for handling {@code StreamSource}s with protection against
* the XML External Entity (XXE) processing vulnerability taking into account * the XML External Entity (XXE) processing vulnerability taking into account
* the value of the {@link #setProcessExternalEntities(boolean)} property. * the value of the {@link #setProcessExternalEntities(boolean)} property.
* <p> * <p>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)}. * to {@link #unmarshalSaxSource(javax.xml.transform.sax.SAXSource)}.
*
* @param streamSource the {@code StreamSource} * @param streamSource the {@code StreamSource}
* @return the object graph * @return the object graph
* @throws IOException if an I/O exception occurs * @throws IOException if an I/O exception occurs
* @throws XmlMappingException if the given source cannot be mapped to an object * @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> * @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; InputSource inputSource;
if (streamSource.getInputStream() != null) { if (streamSource.getInputStream() != null) {
inputSource = new InputSource(streamSource.getInputStream()); inputSource = new InputSource(streamSource.getInputStream());
@ -420,10 +420,9 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
/** /**
* Template method for handling {@code StreamSource}s. * Template method for handling {@code StreamSource}s.
* <p>This implementation defers to {@code unmarshalInputStream} or {@code unmarshalReader}. * <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 #unmarshal(javax.xml.transform.Source)}. The method invoked instead is
* {@link #unmarshalStreamSourceNoExternalEntitities(javax.xml.transform.stream.StreamSource)}. * {@link #unmarshalStreamSourceNoExternalEntitities(javax.xml.transform.stream.StreamSource)}.
*
* @param streamSource the {@code StreamSource} * @param streamSource the {@code StreamSource}
* @return the object graph * @return the object graph
* @throws IOException if an I/O exception occurs * @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) protected abstract void marshalWriter(Object graph, Writer writer)
throws XmlMappingException, IOException; throws XmlMappingException, IOException;
/** /**
* Abstract template method for unmarshalling from a given DOM {@code Node}. * Abstract template method for unmarshalling from a given DOM {@code Node}.
* @param node the DOM node that contains the objects to be unmarshalled * @param node the DOM node that contains the objects to be unmarshalled

42
spring-oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java

@ -113,10 +113,6 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
return this.validating; return this.validating;
} }
@Override
protected String getDefaultEncoding() {
return null;
}
/** /**
* This implementation returns true if the given class is an implementation of {@link XmlObject}. * 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 static class NonClosingInputStream extends InputStream {
private final WeakReference<InputStream> in; private final WeakReference<InputStream> in;
private NonClosingInputStream(InputStream in) { public NonClosingInputStream(InputStream in) {
this.in = new WeakReference<InputStream>(in); this.in = new WeakReference<InputStream>(in);
} }
@ -345,31 +338,31 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
@Override @Override
public int read() throws IOException { public int read() throws IOException {
InputStream in = getInputStream(); InputStream in = getInputStream();
return in != null ? in.read() : -1; return (in != null ? in.read() : -1);
} }
@Override @Override
public int read(byte[] b) throws IOException { public int read(byte[] b) throws IOException {
InputStream in = getInputStream(); InputStream in = getInputStream();
return in != null ? in.read(b) : -1; return (in != null ? in.read(b) : -1);
} }
@Override @Override
public int read(byte[] b, int off, int len) throws IOException { public int read(byte[] b, int off, int len) throws IOException {
InputStream in = getInputStream(); InputStream in = getInputStream();
return in != null ? in.read(b, off, len) : -1; return (in != null ? in.read(b, off, len) : -1);
} }
@Override @Override
public long skip(long n) throws IOException { public long skip(long n) throws IOException {
InputStream in = getInputStream(); InputStream in = getInputStream();
return in != null ? in.skip(n) : 0; return (in != null ? in.skip(n) : 0);
} }
@Override @Override
public boolean markSupported() { public boolean markSupported() {
InputStream in = getInputStream(); InputStream in = getInputStream();
return in != null && in.markSupported(); return (in != null && in.markSupported());
} }
@Override @Override
@ -391,14 +384,14 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
@Override @Override
public int available() throws IOException { public int available() throws IOException {
InputStream in = getInputStream(); InputStream in = getInputStream();
return in != null ? in.available() : 0; return (in != null ? in.available() : 0);
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {
InputStream in = getInputStream(); InputStream in = getInputStream();
if(in != null) { if (in != null) {
this.in.clear(); this.in.clear();
} }
} }
} }
@ -408,7 +401,7 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
private final WeakReference<Reader> reader; private final WeakReference<Reader> reader;
private NonClosingReader(Reader reader) { public NonClosingReader(Reader reader) {
this.reader = new WeakReference<Reader>(reader); this.reader = new WeakReference<Reader>(reader);
} }
@ -419,43 +412,43 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
@Override @Override
public int read(CharBuffer target) throws IOException { public int read(CharBuffer target) throws IOException {
Reader rdr = getReader(); Reader rdr = getReader();
return rdr != null ? rdr.read(target) : -1; return (rdr != null ? rdr.read(target) : -1);
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
Reader rdr = getReader(); Reader rdr = getReader();
return rdr != null ? rdr.read() : -1; return (rdr != null ? rdr.read() : -1);
} }
@Override @Override
public int read(char[] cbuf) throws IOException { public int read(char[] cbuf) throws IOException {
Reader rdr = getReader(); Reader rdr = getReader();
return rdr != null ? rdr.read(cbuf) : -1; return (rdr != null ? rdr.read(cbuf) : -1);
} }
@Override @Override
public int read(char[] cbuf, int off, int len) throws IOException { public int read(char[] cbuf, int off, int len) throws IOException {
Reader rdr = getReader(); Reader rdr = getReader();
return rdr != null ? rdr.read(cbuf, off, len) : -1; return (rdr != null ? rdr.read(cbuf, off, len) : -1);
} }
@Override @Override
public long skip(long n) throws IOException { public long skip(long n) throws IOException {
Reader rdr = getReader(); Reader rdr = getReader();
return rdr != null ? rdr.skip(n) : 0; return (rdr != null ? rdr.skip(n) : 0);
} }
@Override @Override
public boolean ready() throws IOException { public boolean ready() throws IOException {
Reader rdr = getReader(); Reader rdr = getReader();
return rdr != null && rdr.ready(); return (rdr != null && rdr.ready());
} }
@Override @Override
public boolean markSupported() { public boolean markSupported() {
Reader rdr = getReader(); Reader rdr = getReader();
return rdr != null && rdr.markSupported(); return (rdr != null && rdr.markSupported());
} }
@Override @Override
@ -481,7 +474,6 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
this.reader.clear(); this.reader.clear();
} }
} }
} }
} }

Loading…
Cancel
Save