SWS-706 - Jaxp13XPathTemplate should support StreamSources with only a systemId if it's a valid URL
This commit is contained in:
@@ -187,6 +187,17 @@ public abstract class AbstractXomPayloadEndpoint extends TransformerObjectSuppor
|
||||
throw new XomParsingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void source(String systemId) throws Exception {
|
||||
try {
|
||||
Builder builder = new Builder();
|
||||
Document document = builder.build(systemId);
|
||||
element = document.getRootElement();
|
||||
}
|
||||
catch (ParsingException ex) {
|
||||
throw new XomParsingException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class XomParsingException extends NestedRuntimeException {
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
@@ -38,6 +39,7 @@ import javax.xml.stream.XMLStreamWriter;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
@@ -227,6 +229,10 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa
|
||||
public void streamSource(Reader reader) throws IOException, JAXBException {
|
||||
result = unmarshaller.unmarshal(reader);
|
||||
}
|
||||
|
||||
public void source(String systemId) throws Exception {
|
||||
result = unmarshaller.unmarshal(new URL(systemId));
|
||||
}
|
||||
}
|
||||
|
||||
private class JaxbElementSourceCallback<T> implements TraxUtils.SourceCallback {
|
||||
@@ -265,6 +271,10 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa
|
||||
public void streamSource(Reader reader) throws IOException, JAXBException {
|
||||
result = unmarshaller.unmarshal(new StreamSource(reader), declaredType);
|
||||
}
|
||||
|
||||
public void source(String systemId) throws Exception {
|
||||
result = unmarshaller.unmarshal(new StreamSource(systemId), declaredType);
|
||||
}
|
||||
}
|
||||
|
||||
private class Jaxb2ResultCallback implements TraxUtils.ResultCallback {
|
||||
@@ -301,6 +311,10 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa
|
||||
public void streamResult(Writer writer) throws JAXBException {
|
||||
marshaller.marshal(jaxbElement, writer);
|
||||
}
|
||||
|
||||
public void result(String systemId) throws Exception {
|
||||
marshaller.marshal(jaxbElement, new StreamResult(systemId));
|
||||
}
|
||||
}
|
||||
|
||||
private class JaxbStreamingPayload implements StreamingPayload {
|
||||
|
||||
@@ -143,6 +143,10 @@ public abstract class PayloadRootUtils {
|
||||
public void streamSource(Reader reader) throws Exception {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public void source(String systemId) throws Exception {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import javax.xml.transform.stax.StAXSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.StaxUtils;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
@@ -207,38 +208,41 @@ public abstract class TraxUtils {
|
||||
public static void doWithSource(Source source, SourceCallback callback) throws Exception {
|
||||
if (source instanceof DOMSource) {
|
||||
callback.domSource(((DOMSource) source).getNode());
|
||||
return;
|
||||
}
|
||||
else if (isStaxSource(source)) {
|
||||
XMLStreamReader streamReader = getXMLStreamReader(source);
|
||||
if (streamReader != null) {
|
||||
callback.staxSource(streamReader);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
XMLEventReader eventReader = getXMLEventReader(source);
|
||||
if (eventReader != null) {
|
||||
callback.staxSource(eventReader);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"StAX source contains neither XMLStreamReader nor XMLEventReader");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (source instanceof SAXSource) {
|
||||
SAXSource saxSource = (SAXSource) source;
|
||||
callback.saxSource(saxSource.getXMLReader(), saxSource.getInputSource());
|
||||
return;
|
||||
}
|
||||
else if (source instanceof StreamSource) {
|
||||
StreamSource streamSource = (StreamSource) source;
|
||||
if (streamSource.getInputStream() != null) {
|
||||
callback.streamSource(streamSource.getInputStream());
|
||||
return;
|
||||
}
|
||||
else if (streamSource.getReader() != null) {
|
||||
callback.streamSource(streamSource.getReader());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
|
||||
}
|
||||
}
|
||||
if (StringUtils.hasLength(source.getSystemId())) {
|
||||
String systemId = source.getSystemId();
|
||||
callback.source(systemId);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown Source type: " + source.getClass());
|
||||
@@ -246,8 +250,8 @@ public abstract class TraxUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the given {@linkplain ResultCallback callback} operation on a {@link Result}. Supports both the JAXP 1.4
|
||||
* {@link StAXResult} and the Spring 3.0 {@link StaxUtils#createStaxResult StaxSource}.
|
||||
* Performs the given {@linkplain org.springframework.xml.transform.TraxUtils.ResultCallback callback} operation on a {@link javax.xml.transform.Result}. Supports both the JAXP 1.4
|
||||
* {@link javax.xml.transform.stax.StAXResult} and the Spring 3.0 {@link org.springframework.util.xml.StaxUtils#createStaxResult StaxSource}.
|
||||
*
|
||||
* @param result result to look at
|
||||
* @param callback the callback to invoke for each kind of result
|
||||
@@ -255,38 +259,41 @@ public abstract class TraxUtils {
|
||||
public static void doWithResult(Result result, ResultCallback callback) throws Exception{
|
||||
if (result instanceof DOMResult) {
|
||||
callback.domResult(((DOMResult) result).getNode());
|
||||
return;
|
||||
}
|
||||
else if (isStaxResult(result)) {
|
||||
XMLStreamWriter streamWriter = getXMLStreamWriter(result);
|
||||
if (streamWriter != null) {
|
||||
callback.staxResult(streamWriter);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
XMLEventWriter eventWriter = getXMLEventWriter(result);
|
||||
if (eventWriter != null) {
|
||||
callback.staxResult(eventWriter);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"StAX result contains neither XMLStreamWriter nor XMLEventWriter");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (result instanceof SAXResult) {
|
||||
SAXResult saxSource = (SAXResult) result;
|
||||
callback.saxResult(saxSource.getHandler(), saxSource.getLexicalHandler());
|
||||
return;
|
||||
}
|
||||
else if (result instanceof StreamResult) {
|
||||
StreamResult streamSource = (StreamResult) result;
|
||||
if (streamSource.getOutputStream() != null) {
|
||||
callback.streamResult(streamSource.getOutputStream());
|
||||
return;
|
||||
}
|
||||
else if (streamSource.getWriter() != null) {
|
||||
callback.streamResult(streamSource.getWriter());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("StreamResult contains neither OutputStream nor Writer");
|
||||
}
|
||||
}
|
||||
if (StringUtils.hasLength(result.getSystemId())) {
|
||||
String systemId = result.getSystemId();
|
||||
callback.result(systemId);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown Result type: " + result.getClass());
|
||||
@@ -344,6 +351,15 @@ public abstract class TraxUtils {
|
||||
* @param reader the reader
|
||||
*/
|
||||
void streamSource(Reader reader) throws Exception;
|
||||
|
||||
/**
|
||||
* Perform an operation on the system identifier contained in any {@link Source}.
|
||||
*
|
||||
* @param systemId the system identifier
|
||||
*/
|
||||
void source(String systemId) throws Exception;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -398,6 +414,14 @@ public abstract class TraxUtils {
|
||||
* @param writer the writer
|
||||
*/
|
||||
void streamResult(Writer writer) throws Exception;
|
||||
|
||||
/**
|
||||
* Perform an operation on the system identifier contained in any {@link Result}.
|
||||
*
|
||||
* @param systemId the system identifier
|
||||
*/
|
||||
void result(String systemId) throws Exception;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,32 +16,40 @@
|
||||
|
||||
package org.springframework.xml.xpath;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import javax.xml.xpath.XPathFactoryConfigurationException;
|
||||
|
||||
import org.springframework.util.xml.StaxUtils;
|
||||
import org.springframework.xml.namespace.SimpleNamespaceContext;
|
||||
import org.springframework.xml.transform.StaxSource;
|
||||
import org.springframework.xml.transform.TransformerHelper;
|
||||
import org.springframework.xml.transform.TraxUtils;
|
||||
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
* Implementation of {@link XPathOperations} that uses JAXP 1.3. JAXP 1.3 is part of Java SE since 1.5.
|
||||
* <p/>
|
||||
* Namespaces can be set using the <code>namespaces</code> property.
|
||||
* Namespaces can be set using the {@code namespaces} property.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setNamespaces(java.util.Map)
|
||||
@@ -128,35 +136,9 @@ public class Jaxp13XPathTemplate extends AbstractXPathTemplate {
|
||||
xpath.setNamespaceContext(namespaceContext);
|
||||
}
|
||||
try {
|
||||
if (StaxUtils.isStaxSource(context)) {
|
||||
Element element = getRootElement(context);
|
||||
return xpath.evaluate(expression, element, returnType);
|
||||
}
|
||||
else if (context instanceof SAXSource) {
|
||||
SAXSource saxSource = (SAXSource) context;
|
||||
return xpath.evaluate(expression, saxSource.getInputSource(), returnType);
|
||||
}
|
||||
else if (context instanceof DOMSource) {
|
||||
DOMSource domSource = (DOMSource) context;
|
||||
return xpath.evaluate(expression, domSource.getNode(), returnType);
|
||||
}
|
||||
else if (context instanceof StreamSource) {
|
||||
StreamSource streamSource = (StreamSource) context;
|
||||
InputSource inputSource;
|
||||
if (streamSource.getInputStream() != null) {
|
||||
inputSource = new InputSource(streamSource.getInputStream());
|
||||
}
|
||||
else if (streamSource.getReader() != null) {
|
||||
inputSource = new InputSource(streamSource.getReader());
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
|
||||
}
|
||||
return xpath.evaluate(expression, inputSource, returnType);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("context type unknown");
|
||||
}
|
||||
EvaluationCallback callback = new EvaluationCallback(xpath, expression, returnType);
|
||||
TraxUtils.doWithSource(context, callback);
|
||||
return callback.result;
|
||||
}
|
||||
catch (javax.xml.xpath.XPathException ex) {
|
||||
throw new XPathException("Could not evaluate XPath expression [" + expression + "]", ex);
|
||||
@@ -164,11 +146,77 @@ public class Jaxp13XPathTemplate extends AbstractXPathTemplate {
|
||||
catch (TransformerException ex) {
|
||||
throw new XPathException("Could not transform context to DOM Node", ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new XPathException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized XPath createXPath() {
|
||||
return xpathFactory.newXPath();
|
||||
}
|
||||
|
||||
private static class EvaluationCallback implements TraxUtils.SourceCallback {
|
||||
|
||||
private final XPath xpath;
|
||||
|
||||
private final String expression;
|
||||
|
||||
private final QName returnType;
|
||||
|
||||
private final TransformerHelper transformerHelper = new TransformerHelper();
|
||||
|
||||
private Object result;
|
||||
|
||||
private EvaluationCallback(XPath xpath, String expression, QName returnType) {
|
||||
this.xpath = xpath;
|
||||
this.expression = expression;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
public void domSource(Node node) throws XPathExpressionException {
|
||||
result = xpath.evaluate(expression, node, returnType);
|
||||
}
|
||||
|
||||
public void saxSource(XMLReader reader, InputSource inputSource) throws XPathExpressionException {
|
||||
inputSource(inputSource);
|
||||
}
|
||||
|
||||
public void staxSource(XMLEventReader eventReader)
|
||||
throws XPathExpressionException, XMLStreamException, TransformerException {
|
||||
Element element = getRootElement(new StaxSource(eventReader));
|
||||
domSource(element);
|
||||
}
|
||||
|
||||
public void staxSource(XMLStreamReader streamReader) throws TransformerException, XPathExpressionException {
|
||||
Element element = getRootElement(new StaxSource(streamReader));
|
||||
domSource(element);
|
||||
}
|
||||
|
||||
public void streamSource(InputStream inputStream) throws XPathExpressionException {
|
||||
inputSource(new InputSource(inputStream));
|
||||
}
|
||||
|
||||
public void streamSource(Reader reader) throws XPathExpressionException {
|
||||
inputSource(new InputSource(reader));
|
||||
}
|
||||
|
||||
public void source(String systemId) throws XPathExpressionException {
|
||||
inputSource(new InputSource(systemId));
|
||||
}
|
||||
|
||||
private void inputSource(InputSource inputSource) throws XPathExpressionException {
|
||||
result = xpath.evaluate(expression, inputSource, returnType);
|
||||
}
|
||||
|
||||
private Element getRootElement(Source source) throws TransformerException {
|
||||
DOMResult domResult = new DOMResult();
|
||||
transformerHelper.transform(source, domResult);
|
||||
Document document = (Document) domResult.getNode();
|
||||
return document.getDocumentElement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -253,6 +253,35 @@ public class TraxUtilsTest {
|
||||
verify(mock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoWithSystemIdSource() throws Exception {
|
||||
String systemId = "http://www.springframework.org/dtd/spring-beans.dtd";
|
||||
|
||||
TraxUtils.SourceCallback mock = createMock(TraxUtils.SourceCallback.class);
|
||||
mock.source(systemId);
|
||||
|
||||
replay(mock);
|
||||
|
||||
TraxUtils.doWithSource(new StreamSource(systemId), mock);
|
||||
|
||||
verify(mock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoWithSystemIdResult() throws Exception {
|
||||
String systemId = "http://www.springframework.org/dtd/spring-beans.dtd";
|
||||
|
||||
TraxUtils.ResultCallback mock = createMock(TraxUtils.ResultCallback.class);
|
||||
mock.result(systemId);
|
||||
|
||||
replay(mock);
|
||||
|
||||
TraxUtils.doWithResult(new StreamResult(systemId), mock);
|
||||
|
||||
verify(mock);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDoWithInvalidSource() throws Exception {
|
||||
Source source = new Source() {
|
||||
|
||||
@@ -18,12 +18,17 @@ package org.springframework.xml.xpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.stax.StAXSource;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
@@ -36,6 +41,7 @@ import org.junit.Test;
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public abstract class AbstractXPathTemplateTestCase {
|
||||
@@ -133,9 +139,34 @@ public abstract class AbstractXPathTemplateTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateStreamSource() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testEvaluateSAXSource() throws Exception {
|
||||
InputStream in = AbstractXPathTemplateTestCase.class.getResourceAsStream("nonamespaces.xml");
|
||||
String result = template.evaluateAsString("/root/child/text", new StreamSource(in));
|
||||
SAXSource source = new SAXSource(new InputSource(in));
|
||||
String result = template.evaluateAsString("/root/child/text", source);
|
||||
Assert.assertEquals("Invalid result", "text", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateStaxSource() throws Exception {
|
||||
InputStream in = AbstractXPathTemplateTestCase.class.getResourceAsStream("nonamespaces.xml");
|
||||
XMLStreamReader streamReader = XMLInputFactory.newFactory().createXMLStreamReader(in);
|
||||
StAXSource source = new StAXSource(streamReader);
|
||||
String result = template.evaluateAsString("/root/child/text", source);
|
||||
Assert.assertEquals("Invalid result", "text", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateStreamSourceInputStream() throws IOException, SAXException, ParserConfigurationException {
|
||||
InputStream in = AbstractXPathTemplateTestCase.class.getResourceAsStream("nonamespaces.xml");
|
||||
StreamSource source = new StreamSource(in);
|
||||
String result = template.evaluateAsString("/root/child/text", source);
|
||||
Assert.assertEquals("Invalid result", "text", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateStreamSourceSystemId() throws IOException, SAXException, ParserConfigurationException {
|
||||
URL url = AbstractXPathTemplateTestCase.class.getResource("nonamespaces.xml");
|
||||
String result = template.evaluateAsString("/root/child/text", new StreamSource(url.toString()));
|
||||
Assert.assertEquals("Invalid result", "text", result);
|
||||
}
|
||||
|
||||
@@ -152,7 +183,7 @@ public abstract class AbstractXPathTemplateTestCase {
|
||||
|
||||
@Test
|
||||
public void testEvaluateAsObject() throws Exception {
|
||||
String result = (String) template.evaluateAsObject("/root/child", nonamespaces, new NodeMapper<String>() {
|
||||
String result = template.evaluateAsObject("/root/child", nonamespaces, new NodeMapper<String>() {
|
||||
public String mapNode(Node node, int nodeNum) throws DOMException {
|
||||
return node.getLocalName();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user