From 8df063b19e60f5af386e259e88f06a51168bf2e8 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 6 Jan 2009 11:18:27 +0000 Subject: [PATCH] Initial import of OXM module git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@511 50f2f4bb-b051-0410-bef5-90022cba6387 --- org.springframework.oxm/build.xml | 6 + org.springframework.oxm/ivy.xml | 46 ++ org.springframework.oxm/oxm.iml | 96 +++ .../oxm/AbstractMarshaller.java | 496 +++++++++++++++ .../oxm/GenericMarshaller.java | 40 ++ .../GenericMarshallingFailureException.java | 38 ++ .../oxm/GenericUnmarshaller.java | 40 ++ .../org/springframework/oxm/Marshaller.java | 53 ++ .../oxm/MarshallingFailureException.java | 44 ++ .../oxm/UncategorizedXmlMappingException.java | 30 + .../org/springframework/oxm/Unmarshaller.java | 50 ++ .../oxm/UnmarshallingFailureException.java | 35 ++ .../oxm/ValidationFailureException.java | 35 ++ .../oxm/XmlMappingException.java | 37 ++ .../oxm/castor/CastorMarshaller.java | 433 +++++++++++++ .../CastorMarshallingFailureException.java | 34 + .../oxm/castor/CastorSystemException.java | 32 + .../CastorUnmarshallingFailureException.java | 38 ++ .../oxm/castor/CastorUtils.java | 60 ++ .../CastorValidationFailureException.java | 33 + .../springframework/oxm/castor/package.html | 6 + .../Jaxb1MarshallerBeanDefinitionParser.java | 36 ++ .../Jaxb2MarshallerBeanDefinitionParser.java | 61 ++ .../JibxMarshallerBeanDefinitionParser.java | 37 ++ .../oxm/config/OxmNamespaceHandler.java | 36 ++ ...mlBeansMarshallerBeanDefinitionParser.java | 46 ++ .../springframework/oxm/config/package.html | 5 + .../oxm/jaxb/AbstractJaxbMarshaller.java | 208 +++++++ .../oxm/jaxb/Jaxb1Marshaller.java | 152 +++++ .../oxm/jaxb/Jaxb2Marshaller.java | 579 ++++++++++++++++++ .../jaxb/JaxbMarshallingFailureException.java | 35 ++ .../oxm/jaxb/JaxbSystemException.java | 35 ++ .../JaxbUnmarshallingFailureException.java | 38 ++ .../springframework/oxm/jaxb/JaxbUtils.java | 84 +++ .../jaxb/JaxbValidationFailureException.java | 35 ++ .../org/springframework/oxm/jaxb/package.html | 6 + .../oxm/jibx/JibxMarshaller.java | 361 +++++++++++ .../jibx/JibxMarshallingFailureException.java | 34 + .../oxm/jibx/JibxSystemException.java | 34 + .../JibxUnmarshallingFailureException.java | 35 ++ .../springframework/oxm/jibx/JibxUtils.java | 56 ++ .../jibx/JibxValidationFailureException.java | 35 ++ .../org/springframework/oxm/jibx/package.html | 6 + .../oxm/mime/MimeContainer.java | 62 ++ .../oxm/mime/MimeMarshaller.java | 50 ++ .../oxm/mime/MimeUnmarshaller.java | 48 ++ .../org/springframework/oxm/mime/package.html | 5 + .../java/org/springframework/oxm/package.html | 6 + .../support/MarshallingMessageConverter.java | 306 +++++++++ .../oxm/support/MarshallingSource.java | 104 ++++ .../oxm/support/MarshallingView.java | 134 ++++ .../springframework/oxm/support/package.html | 7 + .../oxm/xmlbeans/XmlBeansMarshaller.java | 257 ++++++++ .../XmlBeansMarshallingFailureException.java | 39 ++ .../oxm/xmlbeans/XmlBeansSystemException.java | 33 + ...XmlBeansUnmarshallingFailureException.java | 39 ++ .../oxm/xmlbeans/XmlBeansUtils.java | 69 +++ .../XmlBeansValidationFailureException.java | 38 ++ .../oxm/xmlbeans/XmlOptionsFactoryBean.java | 79 +++ .../springframework/oxm/xmlbeans/package.html | 5 + .../xstream/AnnotationXStreamMarshaller.java | 53 ++ .../oxm/xstream/XStreamMarshaller.java | 461 ++++++++++++++ .../XStreamMarshallingFailureException.java | 49 ++ .../oxm/xstream/XStreamSystemException.java | 34 + .../XStreamUnmarshallingFailureException.java | 54 ++ .../oxm/xstream/XStreamUtils.java | 73 +++ .../springframework/oxm/xstream/package.html | 5 + .../main/resources/META-INF/spring.handlers | 1 + .../main/resources/META-INF/spring.schemas | 1 + .../oxm/config/spring-oxm-1.5.xsd | 146 +++++ .../src/test/castor/castorbuilder.properties | 0 .../oxm/AbstractMarshallerTestCase.java | 130 ++++ .../oxm/AbstractUnmarshallerTestCase.java | 139 +++++ .../oxm/castor/CastorMarshallerTest.java | 75 +++ .../oxm/castor/CastorUnmarshallerTest.java | 71 +++ .../oxm/castor/CastorUtilsTest.java | 42 ++ .../config/Jaxb2OxmNamespaceHandlerTest.java | 41 ++ .../oxm/config/OxmNamespaceHandlerTest.java | 52 ++ .../jaxb/AbstractJaxbMarshallerTestCase.java | 56 ++ .../oxm/jaxb/BinaryObject.java | 57 ++ .../oxm/jaxb/Jaxb1MarshallerTest.java | 82 +++ .../oxm/jaxb/Jaxb1UnmarshallerTest.java | 46 ++ .../oxm/jaxb/Jaxb2MarshallerTest.java | 329 ++++++++++ .../oxm/jaxb/Jaxb2UnmarshallerTest.java | 196 ++++++ .../oxm/jaxb/JaxbUtilsTest.java | 30 + .../springframework/oxm/jibx/FlightType.java | 30 + .../org/springframework/oxm/jibx/Flights.java | 36 ++ .../oxm/jibx/JibxMarshallerTest.java | 79 +++ .../oxm/jibx/JibxUnmarshallerTest.java | 46 ++ .../oxm/jibx/JibxUtilsTest.java | 39 ++ .../MarshallingMessageConverterTest.java | 156 +++++ .../oxm/support/MarshallingViewTest.java | 135 ++++ .../oxm/xmlbeans/XmlBeansMarshallerTest.java | 59 ++ .../xmlbeans/XmlBeansUnmarshallerTest.java | 89 +++ .../oxm/xmlbeans/XmlBeansUtilsTest.java | 53 ++ .../xmlbeans/XmlOptionsFactoryBeanTest.java | 40 ++ .../AnnotationXStreamMarshallerTest.java | 46 ++ .../springframework/oxm/xstream/Flight.java | 34 + .../oxm/xstream/XStreamMarshallerTest.java | 222 +++++++ .../oxm/xstream/XStreamUnmarshallerTest.java | 84 +++ .../oxm/xstream/XStreamUtilsTest.java | 39 ++ .../src/test/resources/log4j.properties | 6 + .../springframework/oxm/castor/mapping.xml | 31 + .../config/jaxb2OxmNamespaceHandlerTest.xml | 11 + .../oxm/config/oxmNamespaceHandlerTest.xml | 17 + .../org/springframework/oxm/flight.xsd | 20 + .../springframework/oxm/jaxb/spring-ws.png | Bin 0 -> 24355 bytes .../org/springframework/oxm/jibx/binding.xml | 13 + org.springframework.oxm/template.mf | 71 +++ 109 files changed, 8496 insertions(+) create mode 100644 org.springframework.oxm/build.xml create mode 100644 org.springframework.oxm/ivy.xml create mode 100644 org.springframework.oxm/oxm.iml create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/AbstractMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/GenericUnmarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/Marshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/MarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/UncategorizedXmlMappingException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/Unmarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/UnmarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/ValidationFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/XmlMappingException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorSystemException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUnmarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUtils.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorValidationFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/castor/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb1MarshallerBeanDefinitionParser.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb2MarshallerBeanDefinitionParser.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/config/JibxMarshallerBeanDefinitionParser.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/config/OxmNamespaceHandler.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/config/XmlBeansMarshallerBeanDefinitionParser.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/config/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/AbstractJaxbMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb1Marshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbMarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbSystemException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUnmarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUtils.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbValidationFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxSystemException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUnmarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUtils.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxValidationFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeContainer.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/mime/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingMessageConverter.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingSource.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingView.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/support/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansSystemException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUtils.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansValidationFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBean.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/package.html create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/AnnotationXStreamMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamSystemException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUnmarshallingFailureException.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUtils.java create mode 100644 org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/package.html create mode 100644 org.springframework.oxm/src/main/resources/META-INF/spring.handlers create mode 100644 org.springframework.oxm/src/main/resources/META-INF/spring.schemas create mode 100644 org.springframework.oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-1.5.xsd create mode 100644 org.springframework.oxm/src/test/castor/castorbuilder.properties create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractUnmarshallerTestCase.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorMarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUtilsTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/config/Jaxb2OxmNamespaceHandlerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/config/OxmNamespaceHandlerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/AbstractJaxbMarshallerTestCase.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1MarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1UnmarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/JaxbUtilsTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/FlightType.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/Flights.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxMarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUnmarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUtilsTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingMessageConverterTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingViewTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUtilsTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBeanTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/AnnotationXStreamMarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/Flight.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTest.java create mode 100644 org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUtilsTest.java create mode 100644 org.springframework.oxm/src/test/resources/log4j.properties create mode 100644 org.springframework.oxm/src/test/resources/org/springframework/oxm/castor/mapping.xml create mode 100644 org.springframework.oxm/src/test/resources/org/springframework/oxm/config/jaxb2OxmNamespaceHandlerTest.xml create mode 100644 org.springframework.oxm/src/test/resources/org/springframework/oxm/config/oxmNamespaceHandlerTest.xml create mode 100644 org.springframework.oxm/src/test/resources/org/springframework/oxm/flight.xsd create mode 100644 org.springframework.oxm/src/test/resources/org/springframework/oxm/jaxb/spring-ws.png create mode 100644 org.springframework.oxm/src/test/resources/org/springframework/oxm/jibx/binding.xml create mode 100644 org.springframework.oxm/template.mf diff --git a/org.springframework.oxm/build.xml b/org.springframework.oxm/build.xml new file mode 100644 index 00000000000..c9239fb9d3a --- /dev/null +++ b/org.springframework.oxm/build.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/org.springframework.oxm/ivy.xml b/org.springframework.oxm/ivy.xml new file mode 100644 index 00000000000..872ec245644 --- /dev/null +++ b/org.springframework.oxm/ivy.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.oxm/oxm.iml b/org.springframework.oxm/oxm.iml new file mode 100644 index 00000000000..4636982093d --- /dev/null +++ b/org.springframework.oxm/oxm.iml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/AbstractMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/AbstractMarshaller.java new file mode 100644 index 00000000000..fc35d2fa88c --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/AbstractMarshaller.java @@ -0,0 +1,496 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Node; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +import org.springframework.util.Assert; +import org.springframework.xml.transform.StaxSource; +import org.springframework.xml.transform.TraxUtils; + +/** + * Abstract implementation of the Marshaller and Unmarshaller interface. This implementation + * inspects the given Source or Result, and defers further handling to overridable template + * methods. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { + + /** Logger available to subclasses. */ + protected final Log logger = LogFactory.getLog(getClass()); + + private DocumentBuilderFactory documentBuilderFactory; + + /** + * Marshals the object graph with the given root into the provided javax.xml.transform.Result. + *

+ * This implementation inspects the given result, and calls marshalDomResult, + * marshalSaxResult, or marshalStreamResult. + * + * @param graph the root of the object graph to marshal + * @param result the result to marshal to + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IOException if an I/O exception occurs + * @throws IllegalArgumentException if result if neither a DOMResult, + * SAXResult, 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) + */ + public final void marshal(Object graph, Result result) throws XmlMappingException, IOException { + if (result instanceof DOMResult) { + marshalDomResult(graph, (DOMResult) result); + } + else if (TraxUtils.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()); + } + } + + /** + * Unmarshals the given provided javax.xml.transform.Source into an object graph. + *

+ * This implementation inspects the given result, and calls unmarshalDomSource, + * unmarshalSaxSource, or unmarshalStreamSource. + * + * @param source the source to marshal from + * @return the object graph + * @throws XmlMappingException if the given source cannot be mapped to an object + * @throws IOException if an I/O Exception occurs + * @throws IllegalArgumentException if source is neither a DOMSource, a + * SAXSource, nor a StreamSource + * @see #unmarshalDomSource(javax.xml.transform.dom.DOMSource) + * @see #unmarshalSaxSource(javax.xml.transform.sax.SAXSource) + * @see #unmarshalStreamSource(javax.xml.transform.stream.StreamSource) + */ + public final Object unmarshal(Source source) throws XmlMappingException, IOException { + if (source instanceof DOMSource) { + return unmarshalDomSource((DOMSource) source); + } + else if (TraxUtils.isStaxSource(source)) { + return unmarshalStaxSource(source); + } + else if (source instanceof SAXSource) { + return unmarshalSaxSource((SAXSource) source); + } + else if (source instanceof StreamSource) { + return unmarshalStreamSource((StreamSource) source); + } + else { + throw new IllegalArgumentException("Unknown Source type: " + source.getClass()); + } + } + + /** + * Create a DocumentBuilder that this marshaller will use for creating DOM documents when passed an + * empty DOMSource. Can be overridden in subclasses, adding further initialization of the builder. + * + * @param factory the DocumentBuilderFactory that the DocumentBuilder should be created with + * @return the DocumentBuilder + * @throws javax.xml.parsers.ParserConfigurationException + * if thrown by JAXP methods + */ + protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory) + throws ParserConfigurationException { + return factory.newDocumentBuilder(); + } + + /** + * Create a DocumentBuilder that this marshaller will use for creating DOM documents when passed an + * empty DOMSource. The resulting 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 a XMLReader that this marshaller will when passed an empty SAXSource. + * + * @return the XMLReader + * @throws SAXException if thrown by JAXP methods + */ + protected XMLReader createXmlReader() throws SAXException { + return XMLReaderFactory.createXMLReader(); + } + + // + // Marshalling + // + + /** + * Template method for handling DOMResults. This implementation defers to marshalDomNode. + * + * @param graph the root of the object graph to marshal + * @param domResult the DOMResult + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IllegalArgumentException if the domResult is empty + * @see #marshalDomNode(Object,org.w3c.dom.Node) + */ + protected void marshalDomResult(Object graph, DOMResult domResult) throws XmlMappingException { + Assert.notNull(domResult.getNode(), "DOMResult does not contain Node"); + marshalDomNode(graph, domResult.getNode()); + } + + /** + * Template method for handling StaxResults. This implementation defers to + * marshalXMLSteamWriter, or marshalXMLEventConsumer, depending on what is contained in + * the StaxResult. + * + * @param graph the root of the object graph to marshal + * @param staxResult a Spring-WS {@link StaxSource} or JAXP 1.4 {@link StAXSource} + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IllegalArgumentException if the domResult is empty + * @see #marshalDomNode(Object,org.w3c.dom.Node) + */ + protected void marshalStaxResult(Object graph, Result staxResult) throws XmlMappingException { + XMLStreamWriter streamWriter = TraxUtils.getXMLStreamWriter(staxResult); + if (streamWriter != null) { + marshalXmlStreamWriter(graph, streamWriter); + } + else { + XMLEventWriter eventWriter = TraxUtils.getXMLEventWriter(staxResult); + if (eventWriter != null) { + marshalXmlEventWriter(graph, eventWriter); + } + else { + throw new IllegalArgumentException("StaxResult contains neither XMLStreamWriter nor XMLEventConsumer"); + } + } + } + + /** + * Template method for handling SAXResults. This implementation defers to + * marshalSaxHandlers. + * + * @param graph the root of the object graph to marshal + * @param saxResult the SAXResult + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @see #marshalSaxHandlers(Object,org.xml.sax.ContentHandler,org.xml.sax.ext.LexicalHandler) + */ + protected void marshalSaxResult(Object graph, SAXResult saxResult) throws XmlMappingException { + ContentHandler contentHandler = saxResult.getHandler(); + Assert.notNull(contentHandler, "ContentHandler not set on SAXResult"); + LexicalHandler lexicalHandler = saxResult.getLexicalHandler(); + marshalSaxHandlers(graph, contentHandler, lexicalHandler); + } + + /** + * Template method for handling StreamResults. This implementation defers to + * marshalOutputStream, or marshalWriter, depending on what is contained in the + * StreamResult + * + * @param graph the root of the object graph to marshal + * @param streamResult the StreamResult + * @throws IOException if an I/O Exception occurs + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IllegalArgumentException if streamResult contains neither OutputStream nor + * Writer. + */ + protected void marshalStreamResult(Object graph, StreamResult streamResult) + throws XmlMappingException, IOException { + if (streamResult.getOutputStream() != null) { + marshalOutputStream(graph, streamResult.getOutputStream()); + } + else if (streamResult.getWriter() != null) { + marshalWriter(graph, streamResult.getWriter()); + } + else { + throw new IllegalArgumentException("StreamResult contains neither OutputStream nor Writer"); + } + } + + // + // Unmarshalling + // + + /** + * Template method for handling DOMSources. This implementation defers to + * unmarshalDomNode. If the given source is empty, an empty source Document will be + * created as a placeholder. + * + * @param domSource the DOMSource + * @return the object graph + * @throws IllegalArgumentException if the domSource is empty + * @throws XmlMappingException if the given source cannot be mapped to an object + * @see #unmarshalDomNode(org.w3c.dom.Node) + */ + protected Object unmarshalDomSource(DOMSource domSource) throws XmlMappingException { + if (domSource.getNode() == null) { + try { + if (documentBuilderFactory == null) { + documentBuilderFactory = createDocumentBuilderFactory(); + } + DocumentBuilder documentBuilder = createDocumentBuilder(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()); + } + + /** + * Template method for handling StaxSources. This implementation defers to + * unmarshalXmlStreamReader, or unmarshalXmlEventReader. + * + * @param staxSource the StaxSource + * @return the object graph + * @throws XmlMappingException if the given source cannot be mapped to an object + */ + protected Object unmarshalStaxSource(Source staxSource) throws XmlMappingException { + XMLStreamReader streamReader = TraxUtils.getXMLStreamReader(staxSource); + if (streamReader != null) { + return unmarshalXmlStreamReader(streamReader); + } + else { + XMLEventReader eventReader = TraxUtils.getXMLEventReader(staxSource); + if (eventReader != null) { + return unmarshalXmlEventReader(eventReader); + } + else { + throw new IllegalArgumentException("StaxSource contains neither XMLStreamReader nor XMLEventReader"); + } + } + } + + /** + * Template method for handling SAXSources. This implementation defers to + * unmarshalSaxReader. + * + * @param saxSource the SAXSource + * @return the object graph + * @throws XmlMappingException if the given source cannot be mapped to an object + * @throws IOException if an I/O Exception occurs + * @see #unmarshalSaxReader(org.xml.sax.XMLReader,org.xml.sax.InputSource) + */ + protected Object unmarshalSaxSource(SAXSource saxSource) throws XmlMappingException, IOException { + if (saxSource.getXMLReader() == null) { + try { + saxSource.setXMLReader(createXmlReader()); + } + catch (SAXException ex) { + throw new UnmarshallingFailureException("Could not create XMLReader for SAXSource: " + ex.getMessage(), + ex); + } + } + if (saxSource.getInputSource() == null) { + saxSource.setInputSource(new InputSource()); + } + return unmarshalSaxReader(saxSource.getXMLReader(), saxSource.getInputSource()); + } + + /** + * Template method for handling StreamSources. This implementation defers to + * unmarshalInputStream, or unmarshalReader. + * + * @param streamSource the 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 + */ + protected Object unmarshalStreamSource(StreamSource streamSource) throws XmlMappingException, IOException { + if (streamSource.getInputStream() != null) { + return unmarshalInputStream(streamSource.getInputStream()); + } + else if (streamSource.getReader() != null) { + return unmarshalReader(streamSource.getReader()); + } + else { + throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader"); + } + } + + // + // Abstract template methods + // + + /** + * Abstract template method for marshalling the given object graph to a DOM Node. + *

+ * In practice, node is be a Document node, a DocumentFragment node, or a + * Element node. In other words, a node that accepts children. + * + * @param graph the root of the object graph to marshal + * @param node The DOM node that will contain the result tree + * @throws XmlMappingException if the given object cannot be marshalled to the DOM node + * @see org.w3c.dom.Document + * @see org.w3c.dom.DocumentFragment + * @see org.w3c.dom.Element + */ + protected abstract void marshalDomNode(Object graph, Node node) throws XmlMappingException; + + /** + * Abstract template method for marshalling the given object to a StAX XMLEventWriter. + * + * @param graph the root of the object graph to marshal + * @param eventWriter the XMLEventWriter to write to + * @throws XmlMappingException if the given object cannot be marshalled to the DOM node + */ + protected abstract void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException; + + /** + * Abstract template method for marshalling the given object to a StAX XMLStreamWriter. + * + * @param graph the root of the object graph to marshal + * @param streamWriter the XMLStreamWriter to write to + * @throws XmlMappingException if the given object cannot be marshalled to the DOM node + */ + protected abstract void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) + throws XmlMappingException; + + /** + * Abstract template method for marshalling the given object graph to a OutputStream. + * + * @param graph the root of the object graph to marshal + * @param outputStream the OutputStream to write to + * @throws XmlMappingException if the given object cannot be marshalled to the writer + * @throws IOException if an I/O exception occurs + */ + protected abstract void marshalOutputStream(Object graph, OutputStream outputStream) + throws XmlMappingException, IOException; + + /** + * Abstract template method for marshalling the given object graph to a SAX ContentHandler. + * + * @param graph the root of the object graph to marshal + * @param contentHandler the SAX ContentHandler + * @param lexicalHandler the SAX2 LexicalHandler. Can be null. + * @throws XmlMappingException if the given object cannot be marshalled to the handlers + */ + protected abstract void marshalSaxHandlers(Object graph, + ContentHandler contentHandler, + LexicalHandler lexicalHandler) throws XmlMappingException; + + /** + * Abstract template method for marshalling the given object graph to a Writer. + * + * @param graph the root of the object graph to marshal + * @param writer the Writer to write to + * @throws XmlMappingException if the given object cannot be marshalled to the writer + * @throws IOException if an I/O exception occurs + */ + protected abstract void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException; + + /** + * Abstract template method for unmarshalling from a given DOM Node. + * + * @param node The DOM node that contains the objects to be unmarshalled + * @return the object graph + * @throws XmlMappingException if the given DOM node cannot be mapped to an object + */ + protected abstract Object unmarshalDomNode(Node node) throws XmlMappingException; + + /** + * Abstract template method for unmarshalling from a given Stax XMLEventReader. + * + * @param eventReader The XMLEventReader to read from + * @return the object graph + * @throws XmlMappingException if the given event reader cannot be converted to an object + */ + protected abstract Object unmarshalXmlEventReader(XMLEventReader eventReader) throws XmlMappingException; + + /** + * Abstract template method for unmarshalling from a given Stax XMLStreamReader. + * + * @param streamReader The XMLStreamReader to read from + * @return the object graph + * @throws XmlMappingException if the given stream reader cannot be converted to an object + */ + protected abstract Object unmarshalXmlStreamReader(XMLStreamReader streamReader) throws XmlMappingException; + + /** + * Abstract template method for unmarshalling from a given InputStream. + * + * @param inputStream the InputStreamStream to read from + * @return the object graph + * @throws XmlMappingException if the given stream cannot be converted to an object + * @throws IOException if an I/O exception occurs + */ + protected abstract Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException; + + /** + * Abstract template method for unmarshalling from a given Reader. + * + * @param reader the Reader to read from + * @return the object graph + * @throws XmlMappingException if the given reader cannot be converted to an object + * @throws IOException if an I/O exception occurs + */ + protected abstract Object unmarshalReader(Reader reader) throws XmlMappingException, IOException; + + /** + * Abstract template method for unmarshalling using a given SAX XMLReader and + * InputSource. + * + * @param xmlReader the SAX XMLReader to parse with + * @param inputSource the input source to parse from + * @return the object graph + * @throws XmlMappingException if the given reader and input source cannot be converted to an object + * @throws java.io.IOException if an I/O exception occurs + */ + protected abstract Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) + throws XmlMappingException, IOException; +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshaller.java new file mode 100644 index 00000000000..1acac5e5412 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshaller.java @@ -0,0 +1,40 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +/** + * Extension of the {@link Marshaller} interface that supports Java 5 generics. More specifically, this marshaller adds + * support for the new {@link Type} hierarchy, returned by methods such as {@link Method#getGenericParameterTypes()} and + * {@link Method#getGenericReturnType()}. + * + * @author Arjen Poutsma + * @since 1.0.2 + */ +public interface GenericMarshaller extends Marshaller { + + /** + * Indicates whether this marshaller can marshal instances of the supplied type. + * + * @param type the type that this marshaller is being asked if it can marshal + * @return true if this marshaller can indeed marshal instances of the supplied type; + * false otherwise + */ + boolean supports(Type type); +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshallingFailureException.java new file mode 100644 index 00000000000..9a3904eda9f --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericMarshallingFailureException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +/** + * Base class for exception thrown when a marshalling or unmarshalling error occurs. + * + * @author Arjen Poutsma + * @see MarshallingFailureException + * @see UnmarshallingFailureException + * @since 1.0.0 + */ +public abstract class GenericMarshallingFailureException extends XmlMappingException { + + /** Constructor for GenericMarshallingFailureException. */ + public GenericMarshallingFailureException(String msg) { + super(msg); + } + + /** Constructor for GenericMarshallingFailureException. */ + public GenericMarshallingFailureException(String msg, Throwable ex) { + super(msg, ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericUnmarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericUnmarshaller.java new file mode 100644 index 00000000000..f9bdc6778f2 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/GenericUnmarshaller.java @@ -0,0 +1,40 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +/** + * Extension of the {@link Unmarshaller} interface that supports Java 5 generics. More specifically, this unmarshaller + * adds support for the new {@link Type} hierarchy, returned by methods such as {@link + * Method#getGenericParameterTypes()} and {@link Method#getGenericReturnType()}. + * + * @author Arjen Poutsma + * @since 1.0.2 + */ +public interface GenericUnmarshaller extends Unmarshaller { + + /** + * Indicates whether this unmarshaller can unmarshal instances of the supplied type. + * + * @param type the type that this unmarshaller is being asked if it can marshal + * @return true if this unmarshaller can indeed unmarshal to the supplied type; false + * otherwise + */ + boolean supports(Type type); +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/Marshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/Marshaller.java new file mode 100644 index 00000000000..0f3e7ab6883 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/Marshaller.java @@ -0,0 +1,53 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +import java.io.IOException; +import javax.xml.transform.Result; + +/** + * Defines the contract for Object XML Mapping Marshallers. Implementations of this interface can serialize a given + * Object to an XML Stream. + *

+ * Although the marshal method accepts a java.lang.Object as its first parameter, most + * Marshaller implementations cannot handle arbitrary java.lang.Object. Instead, a object + * class must be registered with the marshaller, or have a common base class. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public interface Marshaller { + + /** + * Marshals the object graph with the given root into the provided {@link Result}. + * + * @param graph the root of the object graph to marshal + * @param result the result to marshal to + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IOException if an I/O exception occurs + */ + void marshal(Object graph, Result result) throws XmlMappingException, IOException; + + /** + * Indicates whether this marshaller can marshal instances of the supplied type. + * + * @param clazz the class that this marshaller is being asked if it can marshal + * @return true if this marshaller can indeed marshal instances of the supplied class; + * false otherwise + */ + boolean supports(Class clazz); + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/MarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/MarshallingFailureException.java new file mode 100644 index 00000000000..011d9573bae --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/MarshallingFailureException.java @@ -0,0 +1,44 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +/** + * Exception thrown on marshalling failure. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class MarshallingFailureException extends GenericMarshallingFailureException { + + /** + * Construct a MarshallingFailureException with the specified detail message. + * + * @param msg the detail message + */ + public MarshallingFailureException(String msg) { + super(msg); + } + + /** + * Construct a MarshallingFailureException with the specified detail message and nested exception. + * + * @param msg the detail message + * @param ex the nested exception + */ + public MarshallingFailureException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/UncategorizedXmlMappingException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/UncategorizedXmlMappingException.java new file mode 100644 index 00000000000..c19a77fe313 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/UncategorizedXmlMappingException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +/** + * Superclass for exceptions that cannot be distinguished further. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public abstract class UncategorizedXmlMappingException extends XmlMappingException { + + /** Constructor for UncategorizedXmlMappingException. */ + protected UncategorizedXmlMappingException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/Unmarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/Unmarshaller.java new file mode 100644 index 00000000000..c12cbbef03f --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/Unmarshaller.java @@ -0,0 +1,50 @@ +/* + * Copyright 2005-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +import java.io.IOException; +import javax.xml.transform.Source; + +/** + * Defines the contract for Object XML Mapping unmarshallers. + *

+ *

Implementations of this interface can deserialize a given XML Stream to an Object graph. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public interface Unmarshaller { + + /** + * Unmarshals the given {@link Source} into an object graph. + * + * @param source the source to marshal from + * @return the object graph + * @throws XmlMappingException if the given source cannot be mapped to an object + * @throws IOException if an I/O Exception occurs + */ + Object unmarshal(Source source) throws XmlMappingException, IOException; + + /** + * Indicates whether this unmarshaller can unmarshal instances of the supplied type. + * + * @param clazz the class that this unmarshaller is being asked if it can marshal + * @return true if this unmarshaller can indeed unmarshal to the supplied class; false + * otherwise + */ + boolean supports(Class clazz); + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/UnmarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/UnmarshallingFailureException.java new file mode 100644 index 00000000000..d6986f22c3c --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/UnmarshallingFailureException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +/** + * Exception thrown on unmarshalling failure. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class UnmarshallingFailureException extends GenericMarshallingFailureException { + + /** Constructor for UnmarshallingFailureException. */ + public UnmarshallingFailureException(String msg) { + super(msg); + } + + /** Constructor for UnmarshallingFailureException. */ + public UnmarshallingFailureException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/ValidationFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/ValidationFailureException.java new file mode 100644 index 00000000000..5e430ec3813 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/ValidationFailureException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +/** + * Exception thrown on marshalling validation failure. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class ValidationFailureException extends XmlMappingException { + + /** Constructor for ValidationFailureException. */ + public ValidationFailureException(String msg) { + super(msg); + } + + /** Constructor for ValidationFailureException. */ + public ValidationFailureException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/XmlMappingException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/XmlMappingException.java new file mode 100644 index 00000000000..12f5575959a --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/XmlMappingException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +import org.springframework.core.NestedRuntimeException; + +/** + * Root of the hierarchy of Object XML Mapping exceptions. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public abstract class XmlMappingException extends NestedRuntimeException { + + /** Constructor for XmlMappingException. */ + public XmlMappingException(String msg) { + super(msg); + } + + /** Constructor for XmlMappingException. */ + public XmlMappingException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java new file mode 100644 index 00000000000..d7d9ea451fe --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java @@ -0,0 +1,433 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.Iterator; +import java.util.Properties; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.exolab.castor.mapping.Mapping; +import org.exolab.castor.mapping.MappingException; +import org.exolab.castor.xml.MarshalException; +import org.exolab.castor.xml.Marshaller; +import org.exolab.castor.xml.ResolverException; +import org.exolab.castor.xml.UnmarshalHandler; +import org.exolab.castor.xml.Unmarshaller; +import org.exolab.castor.xml.XMLContext; +import org.exolab.castor.xml.XMLException; +import org.w3c.dom.Node; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.oxm.AbstractMarshaller; +import org.springframework.oxm.XmlMappingException; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.xml.dom.DomContentHandler; +import org.springframework.xml.sax.SaxUtils; +import org.springframework.xml.stream.StaxEventContentHandler; +import org.springframework.xml.stream.StaxEventXmlReader; +import org.springframework.xml.stream.StaxStreamContentHandler; +import org.springframework.xml.stream.StaxStreamXmlReader; + +/** + * Implementation of the Marshaller interface for Castor. By default, Castor does not require any further + * configuration, though setting a target class or providing a mapping file can be used to have more control over the + * behavior of Castor. + *

+ * If a target class is specified using setTargetClass, the CastorMarshaller can only be used + * to unmarshall XML that represents that specific class. If you want to unmarshall multiple classes, you have to + * provide a mapping file using setMappingLocations. + *

+ * Due to Castor's API, it is required to set the encoding used for writing to output streams. It defaults to + * UTF-8. + * + * @author Arjen Poutsma + * @see #setEncoding(String) + * @see #setTargetClass(Class) + * @see #setMappingLocation(org.springframework.core.io.Resource) + * @see #setMappingLocations(org.springframework.core.io.Resource[]) + * @since 1.0.0 + */ +public class CastorMarshaller extends AbstractMarshaller implements InitializingBean { + + /** The default encoding used for stream access. */ + public static final String DEFAULT_ENCODING = "UTF-8"; + + private Resource[] mappingLocations; + + private String encoding = DEFAULT_ENCODING; + + private Class targetClass; + + private XMLContext xmlContext; + + private boolean validating = false; + + private boolean whitespacePreserve = false; + + private boolean ignoreExtraAttributes = true; + + private boolean ignoreExtraElements = false; + + private Properties namespaceMappings; + + /** Returns whether the Castor {@link Unmarshaller} should ignore attributes that do not match a specific field. */ + public boolean getIgnoreExtraAttributes() { + return ignoreExtraAttributes; + } + + /** + * Sets whether the Castor {@link Unmarshaller} should ignore attributes that do not match a specific field. + * Default is true: extra attributes are ignored. + * + * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraAttributes(boolean) + */ + public void setIgnoreExtraAttributes(boolean ignoreExtraAttributes) { + this.ignoreExtraAttributes = ignoreExtraAttributes; + } + + /** Returns whether the Castor {@link Unmarshaller} should ignore elements that do not match a specific field. */ + public boolean getIgnoreExtraElements() { + return ignoreExtraElements; + } + + /** + * Sets whether the Castor {@link Unmarshaller} should ignore elements that do not match a specific field. Default + * is false, extra attributes are flagged as an error. + * + * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraElements(boolean) + */ + public void setIgnoreExtraElements(boolean ignoreExtraElements) { + this.ignoreExtraElements = ignoreExtraElements; + } + + /** Returns whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace. */ + public boolean getWhitespacePreserve() { + return whitespacePreserve; + } + + /** + * Sets whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace. Default is + * false. + * + * @see org.exolab.castor.xml.Unmarshaller#setWhitespacePreserve(boolean) + */ + public void setWhitespacePreserve(boolean whitespacePreserve) { + this.whitespacePreserve = whitespacePreserve; + } + + /** Returns whether this marshaller should validate in- and outgoing documents. */ + public boolean isValidating() { + return validating; + } + + /** + * Sets whether this marshaller should validate in- and outgoing documents. Default is false. + * + * @see Marshaller#setValidation(boolean) + */ + public void setValidating(boolean validating) { + this.validating = validating; + } + + /** Returns the namespace mappings. Property names are interpreted as namespace prefixes; values are namespace URIs. */ + public Properties getNamespaceMappings() { + return namespaceMappings; + } + + /** + * Sets the namespace mappings. Property names are interpreted as namespace prefixes; values are namespace URIs. + * + * @see org.exolab.castor.xml.Marshaller#setNamespaceMapping(String, String) + */ + public void setNamespaceMappings(Properties namespaceMappings) { + this.namespaceMappings = namespaceMappings; + } + + /** + * Sets the encoding to be used for stream access. If this property is not set, the default encoding is used. + * + * @see #DEFAULT_ENCODING + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** Sets the locations of the Castor XML Mapping files. */ + public void setMappingLocation(Resource mappingLocation) { + mappingLocations = new Resource[]{mappingLocation}; + } + + /** Sets the locations of the Castor XML Mapping files. */ + public void setMappingLocations(Resource[] mappingLocations) { + this.mappingLocations = mappingLocations; + } + + /** + * Sets the Castor target class. If this property is set, this CastorMarshaller is tied to this one + * specific class. Use a mapping file for unmarshalling multiple classes. + *

+ * You cannot set both this property and the mapping (location). + */ + public void setTargetClass(Class targetClass) { + this.targetClass = targetClass; + } + + public final void afterPropertiesSet() throws IOException { + if (mappingLocations != null && targetClass != null) { + throw new IllegalArgumentException("Cannot set both the 'mappingLocations' and 'targetClass' property. " + + "Set targetClass for unmarshalling a single class, and 'mappingLocations' for multiple classes'"); + } + if (logger.isInfoEnabled()) { + if (mappingLocations != null) { + logger.info("Configured using " + StringUtils.arrayToCommaDelimitedString(mappingLocations)); + } + else if (targetClass != null) { + logger.info("Configured for target class [" + targetClass.getName() + "]"); + } + else { + logger.info("Using default configuration"); + } + } + try { + xmlContext = createXMLContext(mappingLocations, targetClass); + } + catch (MappingException ex) { + throw new CastorSystemException("Could not load Castor mapping: " + ex.getMessage(), ex); + } + catch (ResolverException rex) { + throw new CastorSystemException("Could not load Castor mapping: " + rex.getMessage(), rex); + } + } + + /** Returns true for all classes, i.e. Castor supports arbitrary classes. */ + public boolean supports(Class clazz) { + return true; + } + + /** + * Creates the Castor XMLContext. Subclasses can override this to create a custom context. + *

+ * The default implementation loads mapping files if defined, and the target class if not defined. + * + * @return the created resolver + * @throws MappingException when the mapping file cannot be loaded + * @throws IOException in case of I/O errors + * @see XMLContext#addMapping(org.exolab.castor.mapping.Mapping) + * @see XMLContext#addClass(Class) + */ + protected XMLContext createXMLContext(Resource[] mappingLocations, Class targetClass) + throws MappingException, IOException, ResolverException { + XMLContext context = new XMLContext(); + if (!ObjectUtils.isEmpty(mappingLocations)) { + Mapping mapping = new Mapping(); + for (int i = 0; i < mappingLocations.length; i++) { + mapping.loadMapping(SaxUtils.createInputSource(mappingLocations[i])); + } + context.addMapping(mapping); + } + if (targetClass != null) { + context.addClass(targetClass); + } + return context; + } + + // + // Marshalling + // + + protected final void marshalDomNode(Object graph, Node node) throws XmlMappingException { + marshalSaxHandlers(graph, new DomContentHandler(node), null); + } + + protected final void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler) + throws XmlMappingException { + Marshaller marshaller = xmlContext.createMarshaller(); + marshaller.setContentHandler(contentHandler); + marshal(graph, marshaller); + } + + protected final void marshalOutputStream(Object graph, OutputStream outputStream) + throws XmlMappingException, IOException { + marshalWriter(graph, new OutputStreamWriter(outputStream, encoding)); + } + + protected final void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException { + Marshaller marshaller = xmlContext.createMarshaller(); + marshaller.setWriter(writer); + marshal(graph, marshaller); + } + + protected final void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException { + marshalSaxHandlers(graph, new StaxEventContentHandler(eventWriter), null); + } + + protected final void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException { + marshalSaxHandlers(graph, new StaxStreamContentHandler(streamWriter), null); + } + + private void marshal(Object graph, Marshaller marshaller) { + try { + customizeMarshaller(marshaller); + marshaller.marshal(graph); + } + catch (XMLException ex) { + throw convertCastorException(ex, true); + } + } + + /** + * Template method that allows for customizing of the given Castor {@link Marshaller}. + *

+ * Default implementation invokes {@link Marshaller#setValidation(boolean)} with the property set on this + * marshaller, and calls {@link Marshaller#setNamespaceMapping(String, String)} with the {@linkplain + * #setNamespaceMappings(java.util.Properties) namespace mappings}. + */ + protected void customizeMarshaller(Marshaller marshaller) { + marshaller.setValidation(isValidating()); + Properties namespaceMappings = getNamespaceMappings(); + if (namespaceMappings != null) { + for (Iterator iterator = namespaceMappings.keySet().iterator(); iterator.hasNext();) { + String prefix = (String) iterator.next(); + String uri = namespaceMappings.getProperty(prefix); + marshaller.setNamespaceMapping(prefix, uri); + } + } + } + + // + // Unmarshalling + // + + protected final Object unmarshalDomNode(Node node) throws XmlMappingException { + try { + return createUnmarshaller().unmarshal(node); + } + catch (XMLException ex) { + throw convertCastorException(ex, false); + } + } + + protected final Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException { + try { + return createUnmarshaller().unmarshal(new InputSource(inputStream)); + } + catch (XMLException ex) { + throw convertCastorException(ex, false); + } + } + + protected final Object unmarshalReader(Reader reader) throws XmlMappingException, IOException { + try { + return createUnmarshaller().unmarshal(new InputSource(reader)); + } + catch (XMLException ex) { + throw convertCastorException(ex, false); + } + } + + protected final Object unmarshalXmlEventReader(XMLEventReader eventReader) { + XMLReader reader = new StaxEventXmlReader(eventReader); + try { + return unmarshalSaxReader(reader, new InputSource()); + } + catch (IOException ex) { + throw new CastorUnmarshallingFailureException(new MarshalException(ex)); + } + } + + protected final Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) + throws XmlMappingException, IOException { + UnmarshalHandler unmarshalHandler = createUnmarshaller().createHandler(); + try { + ContentHandler contentHandler = Unmarshaller.getContentHandler(unmarshalHandler); + xmlReader.setContentHandler(contentHandler); + xmlReader.parse(inputSource); + return unmarshalHandler.getObject(); + } + catch (SAXException ex) { + throw new CastorUnmarshallingFailureException(ex); + } + } + + protected final Object unmarshalXmlStreamReader(XMLStreamReader streamReader) { + XMLReader reader = new StaxStreamXmlReader(streamReader); + try { + return unmarshalSaxReader(reader, new InputSource()); + } + catch (IOException ex) { + throw new CastorUnmarshallingFailureException(new MarshalException(ex)); + } + } + + private Unmarshaller createUnmarshaller() { + Unmarshaller unmarshaller = xmlContext.createUnmarshaller(); + if (targetClass != null) { + unmarshaller.setClass(targetClass); + unmarshaller.setClassLoader(targetClass.getClassLoader()); + } + customizeUnmarshaller(unmarshaller); + return unmarshaller; + } + + /** + * Template method that allows for customizing of the given Castor {@link Unmarshaller}. + *

+ * Default implementation invokes {@link Unmarshaller#setValidation(boolean)}, {@link + * Unmarshaller#setWhitespacePreserve(boolean)}, {@link Unmarshaller#setIgnoreExtraAttributes(boolean)}, and {@link + * Unmarshaller#setIgnoreExtraElements(boolean)} with the properties set on this marshaller. + */ + protected void customizeUnmarshaller(Unmarshaller unmarshaller) { + unmarshaller.setValidation(isValidating()); + unmarshaller.setWhitespacePreserve(getWhitespacePreserve()); + unmarshaller.setIgnoreExtraAttributes(getIgnoreExtraAttributes()); + unmarshaller.setIgnoreExtraElements(getIgnoreExtraElements()); + } + + /** + * Converts the given CastorException to an appropriate exception from the + * org.springframework.oxm hierarchy. + *

+ * The default implementation delegates to CastorUtils. Can be overridden in subclasses. + *

+ * A boolean flag is used to indicate whether this exception occurs during marshalling or unmarshalling, since + * Castor itself does not make this distinction in its exception hierarchy. + * + * @param ex Castor XMLException that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException + * @see CastorUtils#convertXmlException + */ + public XmlMappingException convertCastorException(XMLException ex, boolean marshalling) { + return CastorUtils.convertXmlException(ex, marshalling); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshallingFailureException.java new file mode 100644 index 00000000000..0a9987acfdc --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshallingFailureException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import org.exolab.castor.xml.MarshalException; +import org.springframework.oxm.MarshallingFailureException; + +/** + * Castor-specific subclass of MarshallingFailureException. + * + * @author Arjen Poutsma + * @see CastorUtils#convertXmlException + * @since 1.0.0 + */ +public class CastorMarshallingFailureException extends MarshallingFailureException { + + public CastorMarshallingFailureException(MarshalException ex) { + super("Castor marshalling exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorSystemException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorSystemException.java new file mode 100644 index 00000000000..6e10d29a912 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorSystemException.java @@ -0,0 +1,32 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import org.springframework.oxm.UncategorizedXmlMappingException; + +/** + * Castor-specific subclass of UncategorizedXmlMappingException, for Castor exceptions that cannot be + * distinguished further. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class CastorSystemException extends UncategorizedXmlMappingException { + + public CastorSystemException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUnmarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUnmarshallingFailureException.java new file mode 100644 index 00000000000..fbb4d20cd6f --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUnmarshallingFailureException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import org.exolab.castor.xml.MarshalException; +import org.springframework.oxm.UnmarshallingFailureException; +import org.xml.sax.SAXException; + +/** + * Castor-specific subclass of UnmarshallingFailureException. + * + * @author Arjen Poutsma + * @see CastorUtils#convertXmlException + * @since 1.0.0 + */ +public class CastorUnmarshallingFailureException extends UnmarshallingFailureException { + + public CastorUnmarshallingFailureException(MarshalException ex) { + super("Castor unmarshalling exception: " + ex.getMessage(), ex); + } + + public CastorUnmarshallingFailureException(SAXException ex) { + super("Castor unmarshalling exception: " + ex.getMessage(), ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUtils.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUtils.java new file mode 100644 index 00000000000..c503a08ce9d --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import org.exolab.castor.xml.MarshalException; +import org.exolab.castor.xml.ValidationException; +import org.exolab.castor.xml.XMLException; +import org.springframework.oxm.XmlMappingException; + +/** + * Generic utility methods for working with Castor. Mainly for internal use within the framework. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class CastorUtils { + + /** + * Converts the given XMLException to an appropriate exception from the + * org.springframework.oxm hierarchy. + *

+ * A boolean flag is used to indicate whether this exception occurs during marshalling or unmarshalling, since + * Castor itself does not make this distinction in its exception hierarchy. + * + * @param ex Castor XMLException that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException + */ + public static XmlMappingException convertXmlException(XMLException ex, boolean marshalling) { + if (ex instanceof MarshalException) { + MarshalException marshalException = (MarshalException) ex; + if (marshalling) { + return new CastorMarshallingFailureException(marshalException); + } + else { + return new CastorUnmarshallingFailureException(marshalException); + } + } + else if (ex instanceof ValidationException) { + return new CastorValidationFailureException((ValidationException) ex); + } + // fallback + return new CastorSystemException("Unknown Castor exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorValidationFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorValidationFailureException.java new file mode 100644 index 00000000000..a8842aaee6b --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorValidationFailureException.java @@ -0,0 +1,33 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import org.exolab.castor.xml.ValidationException; +import org.springframework.oxm.ValidationFailureException; + +/** + * Castor-specific subclass of MarshallingFailureException. + * + * @author Arjen Poutsma + * @see CastorUtils#convertXmlException + * @since 1.0.0 + */ +public class CastorValidationFailureException extends ValidationFailureException { + + public CastorValidationFailureException(ValidationException ex) { + super("Castor validation exception: " + ex.getMessage(), ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/package.html new file mode 100644 index 00000000000..0ba0c30f495 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/package.html @@ -0,0 +1,6 @@ + + +Package providing integration of Castor within Springs O/X Mapping +support. + + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb1MarshallerBeanDefinitionParser.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb1MarshallerBeanDefinitionParser.java new file mode 100644 index 00000000000..1f051a22c99 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb1MarshallerBeanDefinitionParser.java @@ -0,0 +1,36 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; + +/** + * Parser for the <oxm:jaxb1-marshaller/> element. + * + * @author Arjen Poutsma + * @since 1.5.0 + */ +class Jaxb1MarshallerBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser { + + public static final String JAXB1_MARSHALLER_CLASS_NAME = "org.springframework.oxm.jaxb.Jaxb1Marshaller"; + + protected String getBeanClassName(Element element) { + return JAXB1_MARSHALLER_CLASS_NAME; + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb2MarshallerBeanDefinitionParser.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb2MarshallerBeanDefinitionParser.java new file mode 100644 index 00000000000..b9b44e3017e --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/Jaxb2MarshallerBeanDefinitionParser.java @@ -0,0 +1,61 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.config; + +import java.util.Iterator; +import java.util.List; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * Parser for the <oxm:jaxb2-marshaller/> element. + * + * @author Arjen Poutsma + * @since 1.5.0 + */ +class Jaxb2MarshallerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + + private static final String JAXB2_MARSHALLER_CLASS_NAME = "org.springframework.oxm.jaxb.Jaxb2Marshaller"; + + protected String getBeanClassName(Element element) { + return JAXB2_MARSHALLER_CLASS_NAME; + } + + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { + String contextPath = element.getAttribute("contextPath"); + if (StringUtils.hasText(contextPath)) { + beanDefinitionBuilder.addPropertyValue("contextPath", contextPath); + } + List classes = DomUtils.getChildElementsByTagName(element, "class-to-be-bound"); + if (!classes.isEmpty()) { + ManagedList classesToBeBound = new ManagedList(classes.size()); + for (Iterator iterator = classes.iterator(); iterator.hasNext();) { + Element classToBeBound = (Element) iterator.next(); + String className = classToBeBound.getAttribute("name"); + classesToBeBound.add(className); + } + beanDefinitionBuilder.addPropertyValue("classesToBeBound", classesToBeBound); + } + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/config/JibxMarshallerBeanDefinitionParser.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/JibxMarshallerBeanDefinitionParser.java new file mode 100644 index 00000000000..e25ac65cf71 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/JibxMarshallerBeanDefinitionParser.java @@ -0,0 +1,37 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; + +/** + * Parser for the <oxm:jibx-marshaller/> element. + * + * @author Arjen Poutsma + * @since 1.5.0 + */ +class JibxMarshallerBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser { + + private static final String JIBX_MARSHALLER_CLASS_NAME = "org.springframework.oxm.jibx.JibxMarshaller"; + + protected String getBeanClassName(Element element) { + return JIBX_MARSHALLER_CLASS_NAME; + } + +} \ No newline at end of file diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/config/OxmNamespaceHandler.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/OxmNamespaceHandler.java new file mode 100644 index 00000000000..7387b639e42 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/OxmNamespaceHandler.java @@ -0,0 +1,36 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.config; + +import org.springframework.beans.factory.xml.NamespaceHandler; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +/** + * {@link NamespaceHandler} for the 'oxm' namespace. + * + * @author Arjen Poutsma + * @since 1.5.0 + */ +public class OxmNamespaceHandler extends NamespaceHandlerSupport { + + public void init() { + registerBeanDefinitionParser("jaxb1-marshaller", new Jaxb1MarshallerBeanDefinitionParser()); + registerBeanDefinitionParser("jaxb2-marshaller", new Jaxb2MarshallerBeanDefinitionParser()); + registerBeanDefinitionParser("jibx-marshaller", new JibxMarshallerBeanDefinitionParser()); + registerBeanDefinitionParser("xmlbeans-marshaller", new XmlBeansMarshallerBeanDefinitionParser()); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/config/XmlBeansMarshallerBeanDefinitionParser.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/XmlBeansMarshallerBeanDefinitionParser.java new file mode 100644 index 00000000000..b3566d7bad7 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/XmlBeansMarshallerBeanDefinitionParser.java @@ -0,0 +1,46 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; + +/** + * Parser for the <oxm:xmlbeans-marshaller/> element. + * + * @author Arjen Poutsma + * @since 1.5.0 + */ +class XmlBeansMarshallerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + + public static final String XML_BEANS_MARSHALLER_CLASS_NAME = "org.springframework.oxm.xmlbeans.XmlBeansMarshaller"; + + protected String getBeanClassName(Element element) { + return XML_BEANS_MARSHALLER_CLASS_NAME; + } + + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { + String optionsName = element.getAttribute("options"); + if (StringUtils.hasText(optionsName)) { + beanDefinitionBuilder.addPropertyReference("xmlOptions", optionsName); + } + } +} \ No newline at end of file diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/config/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/package.html new file mode 100644 index 00000000000..e110b3618d0 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/config/package.html @@ -0,0 +1,5 @@ + + +Provides an namespace handler for the Spring Object/XML namespace. + + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/AbstractJaxbMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/AbstractJaxbMarshaller.java new file mode 100644 index 00000000000..2212f327aa4 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/AbstractJaxbMarshaller.java @@ -0,0 +1,208 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jaxb; + +import java.util.Iterator; +import java.util.Map; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.ValidationEventHandler; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.oxm.XmlMappingException; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Abstract base class for implementations of the Marshaller and Unmarshaller interfaces that + * use JAXB. This base class is responsible for creating JAXB marshallers from a JAXBContext. + *

+ * JAXB 2.0 added breaking API changes, so specific subclasses must be used for JAXB 1.0 and 2.0 + * (Jaxb1Marshaller and Jaxb2Marshaller respectivaly). + * + * @author Arjen Poutsma + * @see Jaxb1Marshaller + * @see Jaxb2Marshaller + * @since 1.0.0 + */ +public abstract class AbstractJaxbMarshaller + implements org.springframework.oxm.Marshaller, org.springframework.oxm.Unmarshaller, InitializingBean { + + /** Logger available to subclasses. */ + protected final Log logger = LogFactory.getLog(getClass()); + + private String contextPath; + + private Map marshallerProperties; + + private Map unmarshallerProperties; + + private JAXBContext jaxbContext; + + private ValidationEventHandler validationEventHandler; + + /** Returns the JAXB Context path. */ + protected String getContextPath() { + return contextPath; + } + + /** Sets the JAXB Context path. */ + public void setContextPath(String contextPath) { + Assert.notNull(contextPath, "'contextPath' must not be null"); + this.contextPath = contextPath; + } + + /** + * Sets multiple JAXB Context paths. The given array of context paths is converted to a colon-delimited string, as + * supported by JAXB. + */ + public void setContextPaths(String[] contextPaths) { + Assert.notEmpty(contextPaths, "'contextPaths' must not be empty"); + this.contextPath = StringUtils.arrayToDelimitedString(contextPaths, ":"); + } + + /** + * Sets the JAXB Marshaller properties. These properties will be set on the underlying JAXB + * Marshaller, and allow for features such as indentation. + * + * @param properties the properties + * @see javax.xml.bind.Marshaller#setProperty(String,Object) + * @see javax.xml.bind.Marshaller#JAXB_ENCODING + * @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT + * @see javax.xml.bind.Marshaller#JAXB_NO_NAMESPACE_SCHEMA_LOCATION + * @see javax.xml.bind.Marshaller#JAXB_SCHEMA_LOCATION + */ + public void setMarshallerProperties(Map properties) { + this.marshallerProperties = properties; + } + + /** + * Sets the JAXB Unmarshaller properties. These properties will be set on the underlying JAXB + * Unmarshaller. + * + * @param properties the properties + * @see javax.xml.bind.Unmarshaller#setProperty(String,Object) + */ + public void setUnmarshallerProperties(Map properties) { + this.unmarshallerProperties = properties; + } + + /** + * Sets the JAXB validation event handler. This event handler will be called by JAXB if any validation errors are + * encountered during calls to any of the marshal API's. + * + * @param validationEventHandler the event handler + */ + public void setValidationEventHandler(ValidationEventHandler validationEventHandler) { + this.validationEventHandler = validationEventHandler; + } + + /** Returns the {@link JAXBContext} created in {@link #afterPropertiesSet()}. */ + public JAXBContext getJaxbContext() { + return jaxbContext; + } + + public final void afterPropertiesSet() throws Exception { + try { + jaxbContext = createJaxbContext(); + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + /** + * Convert the given JAXBException to an appropriate exception from the + * org.springframework.oxm hierarchy. + *

+ * The default implementation delegates to JaxbUtils. Can be overridden in subclasses. + * + * @param ex JAXBException that occured + * @return the corresponding XmlMappingException instance + * @see JaxbUtils#convertJaxbException + */ + protected XmlMappingException convertJaxbException(JAXBException ex) { + return JaxbUtils.convertJaxbException(ex); + } + + /** Returns a newly created JAXB marshaller. JAXB marshallers are not necessarily thread safe. */ + protected Marshaller createMarshaller() { + try { + Marshaller marshaller = jaxbContext.createMarshaller(); + if (marshallerProperties != null) { + for (Iterator iterator = marshallerProperties.keySet().iterator(); iterator.hasNext();) { + String name = (String) iterator.next(); + marshaller.setProperty(name, marshallerProperties.get(name)); + } + } + if (validationEventHandler != null) { + marshaller.setEventHandler(validationEventHandler); + } + initJaxbMarshaller(marshaller); + return marshaller; + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + /** Returns a newly created JAXB unmarshaller. JAXB unmarshallers are not necessarily thread safe. */ + protected Unmarshaller createUnmarshaller() { + try { + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + if (unmarshallerProperties != null) { + for (Iterator iterator = unmarshallerProperties.keySet().iterator(); iterator.hasNext();) { + String name = (String) iterator.next(); + unmarshaller.setProperty(name, unmarshallerProperties.get(name)); + } + } + if (validationEventHandler != null) { + unmarshaller.setEventHandler(validationEventHandler); + } + initJaxbUnmarshaller(unmarshaller); + return unmarshaller; + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + /** + * Template method that can be overridden by concrete JAXB marshallers for custom initialization behavior. Gets + * called after creation of JAXB Marshaller, and after the respective properties have been set. + *

+ * Default implementation does nothing. + */ + protected void initJaxbMarshaller(Marshaller marshaller) throws JAXBException { + } + + /** + * Template method that can overridden by concrete JAXB marshallers for custom initialization behavior. Gets called + * after creation of JAXB Unmarshaller, and after the respective properties have been set. + *

+ * Default implementation does nothing. + */ + protected void initJaxbUnmarshaller(Unmarshaller unmarshaller) throws JAXBException { + } + + /** Template method that returns a newly created JAXB context. Called from afterPropertiesSet(). */ + protected abstract JAXBContext createJaxbContext() throws Exception; +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb1Marshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb1Marshaller.java new file mode 100644 index 00000000000..b0a79196cdf --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb1Marshaller.java @@ -0,0 +1,152 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import javax.xml.bind.Element; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.Source; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; +import org.springframework.xml.transform.StaxResult; +import org.springframework.xml.transform.StaxSource; +import org.springframework.xml.transform.TraxUtils; + +/** + * Implementation of the Marshaller interface for JAXB 1.0. + *

+ * The typical usage will be to set the contextPath property on this bean, possibly customize the + * marshaller and unmarshaller by setting properties, and validations, and to refer to it. + * + * @author Arjen Poutsma + * @see #setContextPath(String) + * @see #setMarshallerProperties(java.util.Map) + * @see #setUnmarshallerProperties(java.util.Map) + * @see #setValidating(boolean) + * @since 1.0.0 + */ +public class Jaxb1Marshaller extends AbstractJaxbMarshaller implements BeanClassLoaderAware { + + private boolean validating = false; + + private ClassLoader classLoader; + + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** Set if the JAXB Unmarshaller should validate the incoming document. Default is false. */ + public void setValidating(boolean validating) { + this.validating = validating; + } + + public boolean supports(Class clazz) { + if (!Element.class.isAssignableFrom(clazz)) { + return false; + } + if (StringUtils.hasLength(getContextPath())) { + String className = ClassUtils.getQualifiedName(clazz); + int lastDotIndex = className.lastIndexOf('.'); + if (lastDotIndex == -1) { + return false; + } + String packageName = className.substring(0, lastDotIndex); + String[] contextPaths = StringUtils.tokenizeToStringArray(getContextPath(), ":"); + for (int i = 0; i < contextPaths.length; i++) { + if (contextPaths[i].equals(packageName)) { + return true; + } + } + return false; + } + return false; + + } + + protected final JAXBContext createJaxbContext() throws JAXBException { + if (!StringUtils.hasLength(getContextPath())) { + throw new IllegalArgumentException("contextPath is required"); + } + if (logger.isInfoEnabled()) { + logger.info("Creating JAXBContext with context path [" + getContextPath() + "]"); + } + return classLoader != null ? JAXBContext.newInstance(getContextPath(), classLoader) : + JAXBContext.newInstance(getContextPath()); + } + + protected void initJaxbUnmarshaller(Unmarshaller unmarshaller) throws JAXBException { + unmarshaller.setValidating(validating); + } + + public void marshal(Object graph, Result result) { + if (TraxUtils.isStaxResult(result)) { + XMLStreamWriter streamWriter = TraxUtils.getXMLStreamWriter(result); + if (streamWriter != null) { + result = new StaxResult(streamWriter); + } + else { + XMLEventWriter eventWriter = TraxUtils.getXMLEventWriter(result); + if (eventWriter != null) { + result = new StaxResult(eventWriter); + } + else { + throw new IllegalArgumentException( + "StAXResult contains neither XMLStreamWriter nor XMLEventWriter"); + } + } + } + try { + createMarshaller().marshal(graph, result); + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + public Object unmarshal(Source source) { + if (TraxUtils.isStaxSource(source)) { + XMLStreamReader streamReader = TraxUtils.getXMLStreamReader(source); + if (streamReader != null) { + source = new StaxSource(streamReader); + } + else { + XMLEventReader eventReader = TraxUtils.getXMLEventReader(source); + if (eventReader != null) { + source = new StaxSource(eventReader); + } + else { + throw new IllegalArgumentException( + "StAXSource contains neither XMLStreamReader nor XMLEventReader"); + } + } + } + try { + return createUnmarshaller().unmarshal(source); + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java new file mode 100644 index 00000000000..fbc7d999525 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java @@ -0,0 +1,579 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jaxb; + +import java.awt.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.Map; +import java.util.UUID; +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlAdapter; +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.bind.attachment.AttachmentUnmarshaller; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.validation.Schema; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.oxm.GenericMarshaller; +import org.springframework.oxm.GenericUnmarshaller; +import org.springframework.oxm.XmlMappingException; +import org.springframework.oxm.mime.MimeContainer; +import org.springframework.oxm.mime.MimeMarshaller; +import org.springframework.oxm.mime.MimeUnmarshaller; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.xml.transform.TraxUtils; +import org.springframework.xml.validation.SchemaLoaderUtils; + +/** + * Implementation of the Marshaller interface for JAXB 2.0. + *

+ * The typical usage will be to set either the contextPath or the classesToBeBound property on + * this bean, possibly customize the marshaller and unmarshaller by setting properties, schemas, adapters, and + * listeners, and to refer to it. + * + * @author Arjen Poutsma + * @see #setContextPath(String) + * @see #setClassesToBeBound(Class[]) + * @see #setJaxbContextProperties(java.util.Map) + * @see #setMarshallerProperties(java.util.Map) + * @see #setUnmarshallerProperties(java.util.Map) + * @see #setSchema(org.springframework.core.io.Resource) + * @see #setSchemas(org.springframework.core.io.Resource[]) + * @see #setMarshallerListener(javax.xml.bind.Marshaller.Listener) + * @see #setUnmarshallerListener(javax.xml.bind.Unmarshaller.Listener) + * @see #setAdapters(javax.xml.bind.annotation.adapters.XmlAdapter[]) + * @since 1.0.0 + */ +public class Jaxb2Marshaller extends AbstractJaxbMarshaller + implements MimeMarshaller, MimeUnmarshaller, GenericMarshaller, GenericUnmarshaller, BeanClassLoaderAware { + + private ClassLoader classLoader; + + private Resource[] schemaResources; + + private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI; + + private Marshaller.Listener marshallerListener; + + private Unmarshaller.Listener unmarshallerListener; + + private XmlAdapter[] adapters; + + private Schema schema; + + private Class[] classesToBeBound; + + private Map jaxbContextProperties; + + private boolean mtomEnabled = false; + + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Sets the XmlAdapters to be registered with the JAXB Marshaller and + * Unmarshaller + */ + public void setAdapters(XmlAdapter[] adapters) { + this.adapters = adapters; + } + + /** + * Sets the list of java classes to be recognized by a newly created JAXBContext. Setting this property or + * contextPath is required. + * + * @see #setContextPath(String) + */ + public void setClassesToBeBound(Class[] classesToBeBound) { + this.classesToBeBound = classesToBeBound; + } + + /** + * Sets the JAXBContext properties. These implementation-specific properties will be set on the + * JAXBContext. + */ + public void setJaxbContextProperties(Map jaxbContextProperties) { + this.jaxbContextProperties = jaxbContextProperties; + } + + /** Sets the Marshaller.Listener to be registered with the JAXB Marshaller. */ + public void setMarshallerListener(Marshaller.Listener marshallerListener) { + this.marshallerListener = marshallerListener; + } + + /** + * Indicates whether MTOM support should be enabled or not. Default is false, marshalling using + * XOP/MTOM is not enabled. + */ + public void setMtomEnabled(boolean mtomEnabled) { + this.mtomEnabled = mtomEnabled; + } + + /** + * Sets the schema language. Default is the W3C XML Schema: http://www.w3.org/2001/XMLSchema". + * + * @see XMLConstants#W3C_XML_SCHEMA_NS_URI + * @see XMLConstants#RELAXNG_NS_URI + */ + public void setSchemaLanguage(String schemaLanguage) { + this.schemaLanguage = schemaLanguage; + } + + /** Sets the schema resource to use for validation. */ + public void setSchema(Resource schemaResource) { + schemaResources = new Resource[]{schemaResource}; + } + + /** Sets the schema resources to use for validation. */ + public void setSchemas(Resource[] schemaResources) { + this.schemaResources = schemaResources; + } + + /** Sets the Unmarshaller.Listener to be registered with the JAXB Unmarshaller. */ + public void setUnmarshallerListener(Unmarshaller.Listener unmarshallerListener) { + this.unmarshallerListener = unmarshallerListener; + } + + public boolean supports(Type type) { + if (type instanceof Class) { + return supportsInternal((Class) type, true); + } + else if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + if (JAXBElement.class.equals(parameterizedType.getRawType())) { + Assert.isTrue(parameterizedType.getActualTypeArguments().length == 1, + "Invalid amount of parameterized types in JAXBElement"); + Type typeArgument = parameterizedType.getActualTypeArguments()[0]; + if (typeArgument instanceof Class) { + Class clazz = (Class) typeArgument; + if (!isPrimitiveType(clazz) && !isStandardType(clazz) && !supportsInternal(clazz, false)) { + return false; + } + } + else if (typeArgument instanceof GenericArrayType) { + GenericArrayType genericArrayType = (GenericArrayType) typeArgument; + return genericArrayType.getGenericComponentType().equals(Byte.TYPE); + } + else if (!supports(typeArgument)) { + return false; + } + return true; + } + } + return false; + } + + private boolean isPrimitiveType(Class clazz) { + return (Boolean.class.equals(clazz) || Byte.class.equals(clazz) || Short.class.equals(clazz) || + Integer.class.equals(clazz) || Long.class.equals(clazz) || Float.class.equals(clazz) || + Double.class.equals(clazz) || byte[].class.equals(clazz)); + } + + private boolean isStandardType(Class clazz) { + return (String.class.equals(clazz) || BigInteger.class.equals(clazz) || BigDecimal.class.equals(clazz) || + Calendar.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz) || + QName.class.equals(clazz) || URI.class.equals(clazz) || + XMLGregorianCalendar.class.isAssignableFrom(clazz) || Duration.class.isAssignableFrom(clazz) || + Object.class.equals(clazz) || Image.class.isAssignableFrom(clazz) || DataHandler.class.equals(clazz) || + Source.class.isAssignableFrom(clazz) || UUID.class.equals(clazz)); + } + + public boolean supports(Class clazz) { + return supportsInternal(clazz, true); + } + + private boolean supportsInternal(Class clazz, boolean checkForXmlRootElement) { + if (checkForXmlRootElement && clazz.getAnnotation(XmlRootElement.class) == null) { + return false; + } + if (clazz.getAnnotation(XmlType.class) == null) { + return false; + } + if (StringUtils.hasLength(getContextPath())) { + String className = ClassUtils.getQualifiedName(clazz); + int lastDotIndex = className.lastIndexOf('.'); + if (lastDotIndex == -1) { + return false; + } + String packageName = className.substring(0, lastDotIndex); + String[] contextPaths = StringUtils.tokenizeToStringArray(getContextPath(), ":"); + for (int i = 0; i < contextPaths.length; i++) { + if (contextPaths[i].equals(packageName)) { + return true; + } + } + return false; + } + else if (!ObjectUtils.isEmpty(classesToBeBound)) { + return Arrays.asList(classesToBeBound).contains(clazz); + } + return false; + } + + /* + * JAXBContext + */ + + protected JAXBContext createJaxbContext() throws Exception { + if (JaxbUtils.getJaxbVersion() < JaxbUtils.JAXB_2) { + throw new IllegalStateException( + "Cannot use Jaxb2Marshaller in combination with JAXB 1.0. Use Jaxb1Marshaller instead."); + } + if (StringUtils.hasLength(getContextPath()) && !ObjectUtils.isEmpty(classesToBeBound)) { + throw new IllegalArgumentException("specify either contextPath or classesToBeBound property; not both"); + } + if (!ObjectUtils.isEmpty(schemaResources)) { + if (logger.isDebugEnabled()) { + logger.debug( + "Setting validation schema to " + StringUtils.arrayToCommaDelimitedString(schemaResources)); + } + schema = SchemaLoaderUtils.loadSchema(schemaResources, schemaLanguage); + } + if (StringUtils.hasLength(getContextPath())) { + return createJaxbContextFromContextPath(); + } + else if (!ObjectUtils.isEmpty(classesToBeBound)) { + return createJaxbContextFromClasses(); + } + else { + throw new IllegalArgumentException("setting either contextPath or classesToBeBound is required"); + } + } + + private JAXBContext createJaxbContextFromContextPath() throws JAXBException { + if (logger.isInfoEnabled()) { + logger.info("Creating JAXBContext with context path [" + getContextPath() + "]"); + } + if (jaxbContextProperties != null) { + if (classLoader != null) { + return JAXBContext + .newInstance(getContextPath(), classLoader, jaxbContextProperties); + } + else { + return JAXBContext + .newInstance(getContextPath(), ClassUtils.getDefaultClassLoader(), jaxbContextProperties); + } + } + else { + return classLoader != null ? JAXBContext.newInstance(getContextPath(), classLoader) : + JAXBContext.newInstance(getContextPath()); + } + } + + private JAXBContext createJaxbContextFromClasses() throws JAXBException { + if (logger.isInfoEnabled()) { + logger.info("Creating JAXBContext with classes to be bound [" + + StringUtils.arrayToCommaDelimitedString(classesToBeBound) + "]"); + } + if (jaxbContextProperties != null) { + return JAXBContext.newInstance(classesToBeBound, jaxbContextProperties); + } + else { + return JAXBContext.newInstance(classesToBeBound); + } + } + + /* + * Marshaller/Unmarshaller + */ + + protected void initJaxbMarshaller(Marshaller marshaller) throws JAXBException { + if (schema != null) { + marshaller.setSchema(schema); + } + if (marshallerListener != null) { + marshaller.setListener(marshallerListener); + } + if (adapters != null) { + for (int i = 0; i < adapters.length; i++) { + marshaller.setAdapter(adapters[i]); + } + } + } + + protected void initJaxbUnmarshaller(Unmarshaller unmarshaller) throws JAXBException { + if (schema != null) { + unmarshaller.setSchema(schema); + } + if (unmarshallerListener != null) { + unmarshaller.setListener(unmarshallerListener); + } + if (adapters != null) { + for (int i = 0; i < adapters.length; i++) { + unmarshaller.setAdapter(adapters[i]); + } + } + } + + /* + * Marshalling + */ + + public void marshal(Object graph, Result result) throws XmlMappingException { + marshal(graph, result, null); + } + + public void marshal(Object graph, Result result, MimeContainer mimeContainer) throws XmlMappingException { + try { + Marshaller marshaller = createMarshaller(); + if (mtomEnabled && mimeContainer != null) { + marshaller.setAttachmentMarshaller(new Jaxb2AttachmentMarshaller(mimeContainer)); + } + if (TraxUtils.isStaxResult(result)) { + marshalStaxResult(marshaller, graph, result); + } + else { + marshaller.marshal(graph, result); + } + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + private void marshalStaxResult(Marshaller jaxbMarshaller, Object graph, Result staxResult) throws JAXBException { + XMLStreamWriter streamWriter = TraxUtils.getXMLStreamWriter(staxResult); + if (streamWriter != null) { + jaxbMarshaller.marshal(graph, streamWriter); + } + else { + XMLEventWriter eventWriter = TraxUtils.getXMLEventWriter(staxResult); + if (eventWriter != null) { + jaxbMarshaller.marshal(graph, eventWriter); + } + else { + throw new IllegalArgumentException("StAX Result contains neither XMLStreamWriter nor XMLEventConsumer"); + } + } + } + + /* + * Unmarshalling + */ + + public Object unmarshal(Source source) throws XmlMappingException { + return unmarshal(source, null); + } + + public Object unmarshal(Source source, MimeContainer mimeContainer) throws XmlMappingException { + try { + Unmarshaller unmarshaller = createUnmarshaller(); + if (mtomEnabled && mimeContainer != null) { + unmarshaller.setAttachmentUnmarshaller(new Jaxb2AttachmentUnmarshaller(mimeContainer)); + } + if (TraxUtils.isStaxSource(source)) { + return unmarshalStaxSource(unmarshaller, source); + } + else { + return unmarshaller.unmarshal(source); + } + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + private Object unmarshalStaxSource(Unmarshaller jaxbUnmarshaller, Source staxSource) throws JAXBException { + XMLStreamReader streamReader = TraxUtils.getXMLStreamReader(staxSource); + if (streamReader != null) { + return jaxbUnmarshaller.unmarshal(streamReader); + } + else { + XMLEventReader eventReader = TraxUtils.getXMLEventReader(staxSource); + if (eventReader != null) { + return jaxbUnmarshaller.unmarshal(eventReader); + } + else { + throw new IllegalArgumentException("StaxSource contains neither XMLStreamReader nor XMLEventReader"); + } + } + } + + /* + * Inner classes + */ + + private static class Jaxb2AttachmentMarshaller extends AttachmentMarshaller { + + private final MimeContainer mimeContainer; + + public Jaxb2AttachmentMarshaller(MimeContainer mimeContainer) { + this.mimeContainer = mimeContainer; + } + + public String addMtomAttachment(byte[] data, + int offset, + int length, + String mimeType, + String elementNamespace, + String elementLocalName) { + ByteArrayDataSource dataSource = new ByteArrayDataSource(mimeType, data, offset, length); + return addMtomAttachment(new DataHandler(dataSource), elementNamespace, elementLocalName); + } + + public String addMtomAttachment(DataHandler dataHandler, String elementNamespace, String elementLocalName) { + String host = getHost(elementNamespace, dataHandler); + String contentId = UUID.randomUUID() + "@" + host; + mimeContainer.addAttachment("<" + contentId + ">", dataHandler); + try { + contentId = URLEncoder.encode(contentId, "UTF-8"); + } + catch (UnsupportedEncodingException e) { + // ignore + } + return "cid:" + contentId; + } + + private String getHost(String elementNamespace, DataHandler dataHandler) { + try { + URI uri = new URI(elementNamespace); + return uri.getHost(); + } + catch (URISyntaxException e) { + // ignore + } + return dataHandler.getName(); + } + + public String addSwaRefAttachment(DataHandler dataHandler) { + String contentId = UUID.randomUUID() + "@" + dataHandler.getName(); + mimeContainer.addAttachment(contentId, dataHandler); + return contentId; + } + + @Override + public boolean isXOPPackage() { + return mimeContainer.convertToXopPackage(); + } + } + + private static class Jaxb2AttachmentUnmarshaller extends AttachmentUnmarshaller { + + private final MimeContainer mimeContainer; + + public Jaxb2AttachmentUnmarshaller(MimeContainer mimeContainer) { + this.mimeContainer = mimeContainer; + } + + public byte[] getAttachmentAsByteArray(String cid) { + try { + DataHandler dataHandler = getAttachmentAsDataHandler(cid); + return FileCopyUtils.copyToByteArray(dataHandler.getInputStream()); + } + catch (IOException ex) { + throw new JaxbUnmarshallingFailureException(ex); + } + } + + public DataHandler getAttachmentAsDataHandler(String contentId) { + if (contentId.startsWith("cid:")) { + contentId = contentId.substring("cid:".length()); + try { + contentId = URLDecoder.decode(contentId, "UTF-8"); + } + catch (UnsupportedEncodingException e) { + // ignore + } + contentId = '<' + contentId + '>'; + } + return mimeContainer.getAttachment(contentId); + } + + @Override + public boolean isXOPPackage() { + return mimeContainer.isXopPackage(); + } + } + + /* + * DataSource that wraps around a byte array + */ + private static class ByteArrayDataSource implements DataSource { + + private byte[] data; + + private String contentType; + + private int offset; + + private int length; + + public ByteArrayDataSource(String contentType, byte[] data, int offset, int length) { + this.contentType = contentType; + this.data = data; + this.offset = offset; + this.length = length; + } + + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(data, offset, length); + } + + public OutputStream getOutputStream() throws IOException { + throw new UnsupportedOperationException(); + } + + public String getContentType() { + return contentType; + } + + public String getName() { + return "ByteArrayDataSource"; + } + } + +} + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbMarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbMarshallingFailureException.java new file mode 100644 index 00000000000..8a0941b6e2e --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbMarshallingFailureException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import javax.xml.bind.MarshalException; + +import org.springframework.oxm.MarshallingFailureException; + +/** + * JAXB-specific subclass of MarshallingFailureException. + * + * @author Arjen Poutsma + * @see JaxbUtils#convertJaxbException + * @since 1.0.0 + */ +public class JaxbMarshallingFailureException extends MarshallingFailureException { + + public JaxbMarshallingFailureException(MarshalException ex) { + super("JAXB marshalling exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbSystemException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbSystemException.java new file mode 100644 index 00000000000..00a3fa2dee3 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbSystemException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import javax.xml.bind.JAXBException; + +import org.springframework.oxm.UncategorizedXmlMappingException; + +/** + * JAXB-specific subclass of UncategorizedXmlMappingException, for JAXBExceptions that cannot + * be distinguished further. + * + * @author Arjen Poutsma + * @see JaxbUtils#convertJaxbException(javax.xml.bind.JAXBException) + * @since 1.0.0 + */ +public class JaxbSystemException extends UncategorizedXmlMappingException { + + public JaxbSystemException(JAXBException ex) { + super(ex.getMessage(), ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUnmarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUnmarshallingFailureException.java new file mode 100644 index 00000000000..318fba8eb6c --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUnmarshallingFailureException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import java.io.IOException; +import javax.xml.bind.UnmarshalException; + +import org.springframework.oxm.UnmarshallingFailureException; + +/** + * JAXB-specific subclass of UnmarshallingFailureException. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class JaxbUnmarshallingFailureException extends UnmarshallingFailureException { + + public JaxbUnmarshallingFailureException(UnmarshalException ex) { + super("JAXB unmarshalling exception: " + ex.getMessage(), ex); + } + + public JaxbUnmarshallingFailureException(IOException ex) { + super("JAXB unmarshalling exception: " + ex.getMessage(), ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUtils.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUtils.java new file mode 100644 index 00000000000..1a6ba154f53 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.MarshalException; +import javax.xml.bind.UnmarshalException; +import javax.xml.bind.ValidationException; + +import org.springframework.oxm.XmlMappingException; +import org.springframework.util.ClassUtils; + +/** + * Generic utility methods for working with JAXB. Mainly for internal use within the framework. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public abstract class JaxbUtils { + + public static final int JAXB_1 = 0; + + public static final int JAXB_2 = 1; + + private static final String JAXB_2_CLASS_NAME = "javax.xml.bind.Binder"; + + private static int jaxbVersion = JAXB_1; + + static { + try { + ClassUtils.forName(JAXB_2_CLASS_NAME); + jaxbVersion = JAXB_2; + } + catch (ClassNotFoundException ex1) { + // leave JAXB 1 as default + } + } + + /** + * Gets the major JAXB version. This means we can do things like if (getJaxbVersion() <= JAXB_2). + * + * @return a code comparable to the JAXP_XX codes in this class + * @see #JAXB_1 + * @see #JAXB_2 + */ + public static int getJaxbVersion() { + return jaxbVersion; + } + + /** + * Converts the given JAXBException to an appropriate exception from the + * org.springframework.oxm hierarchy. + * + * @param ex JAXBException that occured + * @return the corresponding XmlMappingException + */ + public static XmlMappingException convertJaxbException(JAXBException ex) { + if (ex instanceof MarshalException) { + return new JaxbMarshallingFailureException((MarshalException) ex); + } + else if (ex instanceof UnmarshalException) { + return new JaxbUnmarshallingFailureException((UnmarshalException) ex); + } + else if (ex instanceof ValidationException) { + return new JaxbValidationFailureException((ValidationException) ex); + } + // fallback + return new JaxbSystemException(ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbValidationFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbValidationFailureException.java new file mode 100644 index 00000000000..e87256f50b3 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/JaxbValidationFailureException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import javax.xml.bind.ValidationException; + +import org.springframework.oxm.ValidationFailureException; + +/** + * JAXB-specific subclass of ValidationFailureException. + * + * @author Arjen Poutsma + * @see JaxbUtils#convertJaxbException + * @since 1.0.0 + */ +public class JaxbValidationFailureException extends ValidationFailureException { + + public JaxbValidationFailureException(ValidationException ex) { + super("JAXB validation exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/package.html new file mode 100644 index 00000000000..7b398a83ea8 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/package.html @@ -0,0 +1,6 @@ + + +Package providing integration of JAXB with Springs O/X Mapping +support. + + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java new file mode 100644 index 00000000000..9d68d3a21e1 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java @@ -0,0 +1,361 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.jibx.runtime.BindingDirectory; +import org.jibx.runtime.IBindingFactory; +import org.jibx.runtime.IMarshallingContext; +import org.jibx.runtime.IUnmarshallingContext; +import org.jibx.runtime.IXMLReader; +import org.jibx.runtime.IXMLWriter; +import org.jibx.runtime.JiBXException; +import org.jibx.runtime.impl.MarshallingContext; +import org.jibx.runtime.impl.StAXReaderWrapper; +import org.jibx.runtime.impl.StAXWriter; +import org.jibx.runtime.impl.UnmarshallingContext; +import org.w3c.dom.Node; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.oxm.AbstractMarshaller; +import org.springframework.oxm.XmlMappingException; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.xml.stream.StaxEventContentHandler; +import org.springframework.xml.stream.XmlEventStreamReader; + +/** + * Implementation of the Marshaller and Unmarshaller interfaces for JiBX. + *

+ * The typical usage will be to set the targetClass and optionally the bindingName property on + * this bean, and to refer to it. + * + * @author Arjen Poutsma + * @see org.jibx.runtime.IMarshallingContext + * @see org.jibx.runtime.IUnmarshallingContext + * @since 1.0.0 + */ +public class JibxMarshaller extends AbstractMarshaller implements InitializingBean { + + private Class targetClass; + + private String bindingName; + + private IBindingFactory bindingFactory; + + private static TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + private int indent = -1; + + private String encoding; + + private Boolean standalone; + + /** Sets the optional binding name for this instance. */ + public void setBindingName(String bindingName) { + this.bindingName = bindingName; + } + + /** Sets the target class for this instance. This property is required. */ + public void setTargetClass(Class targetClass) { + this.targetClass = targetClass; + } + + /** Sets the number of nesting indent spaces. Default is -1, i.e. no indentation. */ + public void setIndent(int indent) { + this.indent = indent; + } + + /** Sets the document encoding using for marshalling. Default is UTF-8. */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** Sets the document standalone flag for marshalling. By default, this flag is not present. */ + public void setStandalone(Boolean standalone) { + this.standalone = standalone; + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(targetClass, "targetClass is required"); + if (logger.isInfoEnabled()) { + if (StringUtils.hasLength(bindingName)) { + logger.info("Configured for target class [" + targetClass + "] using binding [" + bindingName + "]"); + } + else { + logger.info("Configured for target class [" + targetClass + "]"); + } + } + try { + if (StringUtils.hasLength(bindingName)) { + bindingFactory = BindingDirectory.getFactory(bindingName, targetClass); + } + else { + bindingFactory = BindingDirectory.getFactory(targetClass); + } + } + catch (JiBXException ex) { + throw new JibxSystemException(ex); + } + } + + public boolean supports(Class clazz) { + Assert.notNull(clazz, "'clazz' must not be null"); + String[] mappedClasses = bindingFactory.getMappedClasses(); + String className = clazz.getName(); + for (int i = 0; i < mappedClasses.length; i++) { + if (className.equals(mappedClasses[i])) { + return true; + } + } + return false; + } + + /** + * Convert the given JiBXException to an appropriate exception from the + * org.springframework.oxm hierarchy. + *

+ * The default implementation delegates to JibxUtils. Can be overridden in subclasses. + *

+ * A boolean flag is used to indicate whether this exception occurs during marshalling or unmarshalling, since JiBX + * itself does not make this distinction in its exception hierarchy. + * + * @param ex JiBXException that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException instance + * @see JibxUtils#convertJibxException(org.jibx.runtime.JiBXException,boolean) + */ + public XmlMappingException convertJibxException(JiBXException ex, boolean marshalling) { + return JibxUtils.convertJibxException(ex, marshalling); + } + + // + // Supported Marshalling + // + + protected void marshalOutputStream(Object graph, OutputStream outputStream) + throws XmlMappingException, IOException { + try { + IMarshallingContext marshallingContext = createMarshallingContext(); + marshallingContext.marshalDocument(graph, encoding, standalone, outputStream); + } + catch (JiBXException ex) { + throw convertJibxException(ex, true); + } + } + + protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException { + try { + IMarshallingContext marshallingContext = createMarshallingContext(); + marshallingContext.marshalDocument(graph, encoding, standalone, writer); + } + catch (JiBXException ex) { + throw convertJibxException(ex, true); + } + } + + protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException { + try { + MarshallingContext marshallingContext = (MarshallingContext) createMarshallingContext(); + IXMLWriter xmlWriter = new StAXWriter(marshallingContext.getNamespaces(), streamWriter); + marshallingContext.setXmlWriter(xmlWriter); + marshallingContext.marshalDocument(graph); + } + catch (JiBXException ex) { + throw convertJibxException(ex, false); + } + } + + // + // Unsupported Marshalling + // + + protected void marshalDomNode(Object graph, Node node) throws XmlMappingException { + try { + // JiBX does not support DOM natively, so we write to a buffer first, and transform that to the Node + ByteArrayOutputStream os = new ByteArrayOutputStream(); + marshalOutputStream(graph, os); + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(new StreamSource(is), new DOMResult(node)); + } + catch (IOException ex) { + throw new JibxSystemException(ex); + } + catch (TransformerException ex) { + throw new JibxSystemException(ex); + } + } + + protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler) + throws XmlMappingException { + try { + // JiBX does not support SAX natively, so we write to a buffer first, and transform that to the handlers + ByteArrayOutputStream os = new ByteArrayOutputStream(); + marshalOutputStream(graph, os); + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + Transformer transformer = transformerFactory.newTransformer(); + SAXResult saxResult = new SAXResult(contentHandler); + saxResult.setLexicalHandler(lexicalHandler); + transformer.transform(new StreamSource(is), saxResult); + } + catch (IOException ex) { + throw new JibxSystemException(ex); + } + catch (TransformerException ex) { + throw new JibxSystemException(ex); + } + } + + protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) { + ContentHandler contentHandler = new StaxEventContentHandler(eventWriter); + marshalSaxHandlers(graph, contentHandler, null); + } + + // + // Unmarshalling + // + + protected Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException { + try { + IUnmarshallingContext unmarshallingContext = createUnmarshallingContext(); + return unmarshallingContext.unmarshalDocument(inputStream, null); + } + catch (JiBXException ex) { + throw convertJibxException(ex, false); + } + } + + protected Object unmarshalReader(Reader reader) throws XmlMappingException, IOException { + try { + IUnmarshallingContext unmarshallingContext = createUnmarshallingContext(); + return unmarshallingContext.unmarshalDocument(reader); + } + catch (JiBXException ex) { + throw convertJibxException(ex, false); + } + } + + protected Object unmarshalXmlStreamReader(XMLStreamReader streamReader) { + try { + UnmarshallingContext unmarshallingContext = (UnmarshallingContext) createUnmarshallingContext(); + IXMLReader xmlReader = new StAXReaderWrapper(streamReader, null, true); + unmarshallingContext.setDocument(xmlReader); + return unmarshallingContext.unmarshalElement(); + } + catch (JiBXException ex) { + throw convertJibxException(ex, false); + } + } + + protected Object unmarshalXmlEventReader(XMLEventReader eventReader) { + try { + XMLStreamReader streamReader = new XmlEventStreamReader(eventReader); + return unmarshalXmlStreamReader(streamReader); + } + catch (XMLStreamException ex) { + throw new JibxSystemException(ex); + } + } + + // + // Unsupported Unmarshalling + // + + protected Object unmarshalDomNode(Node node) throws XmlMappingException { + try { + Transformer transformer = transformerFactory.newTransformer(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + transformer.transform(new DOMSource(node), new StreamResult(os)); + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + return unmarshalInputStream(is); + } + catch (IOException ex) { + throw new JibxSystemException(ex); + } + catch (TransformerException ex) { + throw new JibxSystemException(ex); + } + } + + protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) + throws XmlMappingException, IOException { + try { + Transformer transformer = transformerFactory.newTransformer(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + transformer.transform(new SAXSource(xmlReader, inputSource), new StreamResult(os)); + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + return unmarshalInputStream(is); + } + catch (IOException ex) { + throw new JibxSystemException(ex); + } + catch (TransformerException ex) { + throw new JibxSystemException(ex); + } + } + + /** + * Creates a new IMarshallingContext, set with the correct indentation. + * + * @return the created marshalling context + * @throws JiBXException in case of errors + */ + protected IMarshallingContext createMarshallingContext() throws JiBXException { + IMarshallingContext marshallingContext = bindingFactory.createMarshallingContext(); + marshallingContext.setIndent(indent); + return marshallingContext; + } + + /** + * Creates a new IUnmarshallingContext, set with the correct indentation. + * + * @return the created unmarshalling context + * @throws JiBXException in case of errors + */ + protected IUnmarshallingContext createUnmarshallingContext() throws JiBXException { + return bindingFactory.createUnmarshallingContext(); + } + + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshallingFailureException.java new file mode 100644 index 00000000000..4d9613e9f11 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshallingFailureException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import org.jibx.runtime.JiBXException; +import org.springframework.oxm.MarshallingFailureException; + +/** + * JiXB-specific subclass of MarshallingFailureException. + * + * @author Arjen Poutsma + * @see JibxUtils#convertJibxException(org.jibx.runtime.JiBXException,boolean) + * @since 1.0.0 + */ +public class JibxMarshallingFailureException extends MarshallingFailureException { + + public JibxMarshallingFailureException(JiBXException ex) { + super("JiBX marshalling exception: " + ex.getMessage(), ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxSystemException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxSystemException.java new file mode 100644 index 00000000000..e8962e996c3 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxSystemException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import org.springframework.oxm.UncategorizedXmlMappingException; + +/** + * JiBX-specific subclass of UncategorizedXmlMappingException, for JiBXBExceptions that cannot + * be distinguished further. + * + * @author Arjen Poutsma + * @see JibxUtils#convertJibxException(org.jibx.runtime.JiBXException,boolean) + * @since 1.0.0 + */ +public class JibxSystemException extends UncategorizedXmlMappingException { + + public JibxSystemException(Exception ex) { + super(ex.getMessage(), ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUnmarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUnmarshallingFailureException.java new file mode 100644 index 00000000000..797bbffdfc9 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUnmarshallingFailureException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import org.jibx.runtime.JiBXException; +import org.springframework.oxm.UnmarshallingFailureException; + +/** + * JiXB-specific subclass of UnmarshallingFailureException. + * + * @author Arjen Poutsma + * @see JibxUtils#convertJibxException(org.jibx.runtime.JiBXException,boolean) + * @since 1.0.0 + */ +public class JibxUnmarshallingFailureException extends UnmarshallingFailureException { + + public JibxUnmarshallingFailureException(JiBXException ex) { + super("JiBX unmarshalling exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUtils.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUtils.java new file mode 100644 index 00000000000..56c1b9f03e0 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import org.jibx.runtime.JiBXException; +import org.jibx.runtime.ValidationException; +import org.springframework.oxm.XmlMappingException; + +/** + * Generic utility methods for working with JiBX. Mainly for internal use within the framework. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public abstract class JibxUtils { + + /** + * Converts the given JiBXException to an appropriate exception from the + * org.springframework.oxm hierarchy. + *

+ * A boolean flag is used to indicate whether this exception occurs during marshalling or unmarshalling, since JiBX + * itself does not make this distinction in its exception hierarchy. + * + * @param ex JiBXException that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException + */ + public static XmlMappingException convertJibxException(JiBXException ex, boolean marshalling) { + if (ex instanceof ValidationException) { + return new JibxValidationFailureException((ValidationException) ex); + } + else { + if (marshalling) { + return new JibxMarshallingFailureException(ex); + } + else { + return new JibxUnmarshallingFailureException(ex); + } + } + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxValidationFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxValidationFailureException.java new file mode 100644 index 00000000000..23952b21b58 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxValidationFailureException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import org.jibx.runtime.ValidationException; +import org.springframework.oxm.ValidationFailureException; + +/** + * JAXB-specific subclass of ValidationFailureException. + * + * @author Arjen Poutsma + * @see JibxUtils#convertJibxException(org.jibx.runtime.JiBXException,boolean) + * @since 1.0.0 + */ +public class JibxValidationFailureException extends ValidationFailureException { + + public JibxValidationFailureException(ValidationException ex) { + super("JiBX validation exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/package.html new file mode 100644 index 00000000000..a685b60e4cd --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/package.html @@ -0,0 +1,6 @@ + + +Package providing integration of JiBX with Springs O/X Mapping +support. + + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeContainer.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeContainer.java new file mode 100644 index 00000000000..81767e5d04c --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeContainer.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.mime; + +import javax.activation.DataHandler; + +/** + * Represents a container for MIME attachments. Concrete implementations might adapt a SOAPMesage, or an email message. + * + * @author Arjen Poutsma + * @see XML-binary Optimized Packaging + * @since 1.0.0 + */ +public interface MimeContainer { + + /** + * Indicates whether this container is a XOP package. + * + * @return true when the constraints specified in Identifying + * XOP Documents are met. + * @see XOP Packages + */ + boolean isXopPackage(); + + /** + * Turns this message into a XOP package. + * + * @return true when the message is a XOP package + * @see XOP Packages + */ + boolean convertToXopPackage(); + + /** + * Adds the given data handler as an attachment to this container. + * + * @param contentId the content id of the attachment + * @param dataHandler the data handler containing the data of the attachment + */ + void addAttachment(String contentId, DataHandler dataHandler); + + /** + * Returns the attachment with the given content id, or null if not found. + * + * @param contentId the content id + * @return the attachment, as a data handler + */ + DataHandler getAttachment(String contentId); +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java new file mode 100644 index 00000000000..c7a1e6ee7a1 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java @@ -0,0 +1,50 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.mime; + +import java.io.IOException; +import javax.xml.transform.Result; + +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.XmlMappingException; + +/** + * Subinterface of {@link Marshaller} that can use MIME attachments to optimize storage of binary data. Attachments can + * be added as MTOM, XOP, or SwA. + * + * @author Arjen Poutsma + * @see SOAP Message Transmission Optimization + * Mechanism + * @see XML-binary Optimized Packaging + * @since 1.0.0 + */ +public interface MimeMarshaller extends Marshaller { + + /** + * Marshals the object graph with the given root into the provided {@link Result}, writing binary data to a {@link + * MimeContainer}. + * + * @param graph the root of the object graph to marshal + * @param result the result to marshal to + * @param mimeContainer the MIME container to write extracted binary content to + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IOException if an I/O exception occurs + */ + void marshal(Object graph, Result result, MimeContainer mimeContainer) throws XmlMappingException, IOException; + + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java new file mode 100644 index 00000000000..e6a3edede91 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java @@ -0,0 +1,48 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.mime; + +import java.io.IOException; +import javax.xml.transform.Source; + +import org.springframework.oxm.Unmarshaller; +import org.springframework.oxm.XmlMappingException; + +/** + * Subinterface of {@link org.springframework.oxm.Marshaller} that can use MIME attachments to optimize storage of + * binary data. Attachments can be added as MTOM, XOP, or SwA. + * + * @author Arjen Poutsma + * @see SOAP Message Transmission Optimization + * Mechanism + * @see XML-binary Optimized Packaging + * @since 1.0.0 + */ +public interface MimeUnmarshaller extends Unmarshaller { + + /** + * Unmarshals the given provided {@link Source} into an object graph, reading binary attachments from a {@link + * MimeContainer}. + * + * @param source the source to marshal from + * @param mimeContainer the MIME container to read extracted binary content from + * @return the object graph + * @throws XmlMappingException if the given source cannot be mapped to an object + * @throws IOException if an I/O Exception occurs + */ + Object unmarshal(Source source, MimeContainer mimeContainer) throws XmlMappingException, IOException; +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/package.html new file mode 100644 index 00000000000..c5563d6e6a5 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/mime/package.html @@ -0,0 +1,5 @@ + + +Contains (un)marshallers optimized to store binary data in MIME attachments. + + \ No newline at end of file diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/package.html new file mode 100644 index 00000000000..e7fdb73698c --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/package.html @@ -0,0 +1,6 @@ + + +Root package for Spring's O/X Mapping integration classes. Contains generic Marshaller and Unmarshaller interfaces, +and XmlMappingExceptions related to O/X Mapping. + + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingMessageConverter.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingMessageConverter.java new file mode 100644 index 00000000000..26a2e787983 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingMessageConverter.java @@ -0,0 +1,306 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.support; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.jms.support.converter.MessageConversionException; +import org.springframework.jms.support.converter.MessageConverter; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.MarshallingFailureException; +import org.springframework.oxm.Unmarshaller; +import org.springframework.oxm.UnmarshallingFailureException; +import org.springframework.util.Assert; + +/** + * Spring JMS {@link MessageConverter} that uses a {@link Marshaller} and {@link Unmarshaller}. Marshals an object to a + * {@link BytesMessage}, or to a {@link TextMessage} if the {@link #setMarshalTo marshalTo} is set to {@link + * #MARSHAL_TO_TEXT_MESSAGE}. Unmarshals from a {@link TextMessage} or {@link BytesMessage} to an object. + * + * @author Arjen Poutsma + * @see org.springframework.jms.core.JmsTemplate#convertAndSend + * @see org.springframework.jms.core.JmsTemplate#receiveAndConvert + * @since 1.5.1 + */ +public class MarshallingMessageConverter implements MessageConverter, InitializingBean { + + /** Constant that indicates that {@link #toMessage(Object, Session)} should marshal to a {@link BytesMessage}. */ + public static final int MARSHAL_TO_BYTES_MESSAGE = 1; + + /** Constant that indicates that {@link #toMessage(Object, Session)} should marshal to a {@link TextMessage}. */ + public static final int MARSHAL_TO_TEXT_MESSAGE = 2; + + private Marshaller marshaller; + + private Unmarshaller unmarshaller; + + private int marshalTo = MARSHAL_TO_BYTES_MESSAGE; + + /** + * Constructs a new MarshallingMessageConverter with no {@link Marshaller} set. The marshaller must be + * set after construction by invoking {@link #setMarshaller(Marshaller)}. + */ + public MarshallingMessageConverter() { + } + + /** + * Constructs a new MarshallingMessageConverter with the given {@link Marshaller} set. If the given + * {@link Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and + * unmarshalling. Otherwise, an exception is thrown. + *

+ * Note that all {@link Marshaller} implementations in Spring-WS also implement the {@link Unmarshaller} interface, + * so that you can safely use this constructor. + * + * @param marshaller object used as marshaller and unmarshaller + * @throws IllegalArgumentException when marshaller does not implement the {@link Unmarshaller} + * interface + */ + public MarshallingMessageConverter(Marshaller marshaller) { + Assert.notNull(marshaller, "marshaller must not be null"); + if (!(marshaller instanceof Unmarshaller)) { + throw new IllegalArgumentException("Marshaller [" + marshaller + "] does not implement the Unmarshaller " + + "interface. Please set an Unmarshaller explicitely by using the " + + "AbstractMarshallingPayloadEndpoint(Marshaller, Unmarshaller) constructor."); + } + else { + this.marshaller = marshaller; + this.unmarshaller = (Unmarshaller) marshaller; + } + } + + /** + * Creates a new MarshallingMessageConverter with the given marshaller and unmarshaller. + * + * @param marshaller the marshaller to use + * @param unmarshaller the unmarshaller to use + */ + public MarshallingMessageConverter(Marshaller marshaller, Unmarshaller unmarshaller) { + Assert.notNull(marshaller, "marshaller must not be null"); + Assert.notNull(unmarshaller, "unmarshaller must not be null"); + this.marshaller = marshaller; + this.unmarshaller = unmarshaller; + } + + /** + * Indicates whether {@link #toMessage(Object,Session)} should marshal to a {@link BytesMessage} or a {@link + * TextMessage}. The default is {@link #MARSHAL_TO_BYTES_MESSAGE}, i.e. this converter marshals to a {@link + * BytesMessage}. + * + * @see #MARSHAL_TO_BYTES_MESSAGE + * @see #MARSHAL_TO_TEXT_MESSAGE + */ + public void setMarshalTo(int marshalTo) { + this.marshalTo = marshalTo; + } + + /** Sets the {@link Marshaller} to be used by this message converter. */ + public void setMarshaller(Marshaller marshaller) { + this.marshaller = marshaller; + } + + /** Sets the {@link Unmarshaller} to be used by this message converter. */ + public void setUnmarshaller(Unmarshaller unmarshaller) { + this.unmarshaller = unmarshaller; + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(marshaller, "Property 'marshaller' is required"); + Assert.notNull(unmarshaller, "Property 'unmarshaller' is required"); + } + + /** + * Marshals the given object to a {@link TextMessage} or {@link javax.jms.BytesMessage}. The desired message type + * can be defined by setting the {@link #setMarshalTo(int) marshalTo} property. + * + * @see #marshalToTextMessage + * @see #marshalToBytesMessage + */ + public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException { + try { + switch (marshalTo) { + case MARSHAL_TO_TEXT_MESSAGE: + return marshalToTextMessage(object, session, marshaller); + case MARSHAL_TO_BYTES_MESSAGE: + return marshalToBytesMessage(object, session, marshaller); + default: + return marshalToMessage(object, session, marshaller); + } + } + catch (MarshallingFailureException ex) { + throw new MessageConversionException("Could not marshal [" + object + "]", ex); + } + catch (IOException ex) { + throw new MessageConversionException("Could not marshal [" + object + "]", ex); + } + } + + /** + * Unmarshals the given {@link Message} into an object. + * + * @see #unmarshalFromTextMessage + * @see #unmarshalFromBytesMessage + */ + public Object fromMessage(Message message) throws JMSException, MessageConversionException { + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + return unmarshalFromTextMessage(textMessage, unmarshaller); + } + else if (message instanceof BytesMessage) { + BytesMessage bytesMessage = (BytesMessage) message; + return unmarshalFromBytesMessage(bytesMessage, unmarshaller); + } + else { + return unmarshalFromMessage(message, unmarshaller); + } + } + catch (UnmarshallingFailureException ex) { + throw new MessageConversionException("Could not unmarshal message [" + message + "]", ex); + } + catch (IOException ex) { + throw new MessageConversionException("Could not unmarshal message [" + message + "]", ex); + } + } + + /** + * Marshals the given object to a {@link TextMessage}. + * + * @param object the object to be marshalled + * @param session current JMS session + * @param marshaller the marshaller to use + * @return the resulting message + * @throws JMSException if thrown by JMS methods + * @throws IOException in case of I/O errors + * @see Session#createTextMessage + * @see Marshaller#marshal(Object, Result) + */ + protected TextMessage marshalToTextMessage(Object object, Session session, Marshaller marshaller) + throws JMSException, IOException { + StringWriter writer = new StringWriter(); + Result result = new StreamResult(writer); + marshaller.marshal(object, result); + return session.createTextMessage(writer.toString()); + } + + /** + * Marshals the given object to a {@link BytesMessage}. + * + * @param object the object to be marshalled + * @param session current JMS session + * @param marshaller the marshaller to use + * @return the resulting message + * @throws JMSException if thrown by JMS methods + * @throws IOException in case of I/O errors + * @see Session#createBytesMessage + * @see Marshaller#marshal(Object, Result) + */ + protected BytesMessage marshalToBytesMessage(Object object, Session session, Marshaller marshaller) + throws JMSException, IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + StreamResult streamResult = new StreamResult(bos); + marshaller.marshal(object, streamResult); + BytesMessage message = session.createBytesMessage(); + message.writeBytes(bos.toByteArray()); + return message; + } + + /** + * Template method that allows for custom message marshalling. Invoked when {@link #setMarshalTo(int)} is not {@link + * #MARSHAL_TO_TEXT_MESSAGE} or {@link #MARSHAL_TO_BYTES_MESSAGE}. + *

+ * Default implemenetation throws a {@link MessageConversionException}. + * + * @param object the object to marshal + * @param session the JMS session + * @param marshaller the marshaller to use + * @return the resulting message + * @throws JMSException if thrown by JMS methods + * @throws IOException in case of I/O errors + */ + protected Message marshalToMessage(Object object, Session session, Marshaller marshaller) + throws JMSException, IOException { + throw new MessageConversionException( + "Unknown 'marshalTo' value [" + marshalTo + "]. Cannot convert object to Message"); + } + + /** + * Unmarshals the given {@link TextMessage} into an object. + * + * @param message the message + * @param unmarshaller the unmarshaller to use + * @return the unmarshalled object + * @throws JMSException if thrown by JMS methods + * @throws IOException in case of I/O errors + * @see Unmarshaller#unmarshal(Source) + */ + protected Object unmarshalFromTextMessage(TextMessage message, Unmarshaller unmarshaller) + throws JMSException, IOException { + Source source = new StreamSource(new StringReader(message.getText())); + return unmarshaller.unmarshal(source); + } + + /** + * Unmarshals the given {@link BytesMessage} into an object. + * + * @param message the message + * @param unmarshaller the unmarshaller to use + * @return the unmarshalled object + * @throws JMSException if thrown by JMS methods + * @throws IOException in case of I/O errors + * @see Unmarshaller#unmarshal(Source) + */ + protected Object unmarshalFromBytesMessage(BytesMessage message, Unmarshaller unmarshaller) + throws JMSException, IOException { + byte[] bytes = new byte[(int) message.getBodyLength()]; + message.readBytes(bytes); + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + StreamSource source = new StreamSource(bis); + return unmarshaller.unmarshal(source); + } + + /** + * Template method that allows for custom message unmarshalling. Invoked when {@link #fromMessage(Message)} is + * invoked with a message that is not a {@link TextMessage} or {@link BytesMessage}. + *

+ * Default implemenetation throws a {@link MessageConversionException}. + * + * @param message the message + * @param unmarshaller the unmarshaller to use + * @return the unmarshalled object + * @throws JMSException if thrown by JMS methods + * @throws IOException in case of I/O errors + */ + protected Object unmarshalFromMessage(Message message, Unmarshaller unmarshaller) throws JMSException, IOException { + throw new MessageConversionException( + "MarshallingMessageConverter only supports TextMessages and BytesMessages"); + } +} + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingSource.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingSource.java new file mode 100644 index 00000000000..b0d4c2bd118 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingSource.java @@ -0,0 +1,104 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.support; + +import java.io.IOException; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; + +import org.springframework.oxm.Marshaller; +import org.springframework.util.Assert; +import org.springframework.xml.sax.AbstractXmlReader; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * {@link Source} implementation that uses a {@link Marshaller}.Can be constructed with a Marshaller and an + * object to be marshalled. + *

+ * Even though StaxSource extends from SAXSource, calling the methods of + * SAXSource is not supported. In general, the only supported operation on this class is + * to use the XMLReader obtained via {@link #getXMLReader()} to parse the input source obtained via {@link + * #getInputSource()}. Calling {@link #setXMLReader(org.xml.sax.XMLReader)} or {@link + * #setInputSource(org.xml.sax.InputSource)} will result in UnsupportedOperationExceptions. + * + * @author Arjen Poutsma + * @see javax.xml.transform.Transformer + * @since 1.0.0 + */ +public class MarshallingSource extends SAXSource { + + private final Marshaller marshaller; + + private final Object content; + + /** + * Creates a new MarshallingSource with the given marshaller and content. + * + * @param marshaller the marshaller to use + * @param content the object to be marshalled + */ + public MarshallingSource(Marshaller marshaller, Object content) { + Assert.notNull(marshaller, "'marshaller' must not be null"); + Assert.notNull(content, "'content' must not be null"); + this.marshaller = marshaller; + this.content = content; + setXMLReader(new MarshallingXmlReader()); + setInputSource(new InputSource()); + } + + /** Returns the Marshaller used by this MarshallingSource. */ + public Marshaller getMarshaller() { + return marshaller; + } + + /** Returns the object to be marshalled. */ + public Object getContent() { + return content; + } + + private class MarshallingXmlReader extends AbstractXmlReader { + + public void parse(InputSource input) throws IOException, SAXException { + parse(); + } + + public void parse(String systemId) throws IOException, SAXException { + parse(); + } + + private void parse() throws SAXException { + SAXResult result = new SAXResult(getContentHandler()); + result.setLexicalHandler(getLexicalHandler()); + try { + marshaller.marshal(content, result); + } + catch (IOException ex) { + SAXParseException saxException = new SAXParseException(ex.getMessage(), null, null, -1, -1, ex); + if (getErrorHandler() != null) { + getErrorHandler().fatalError(saxException); + } + else { + throw saxException; + } + } + } + + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingView.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingView.java new file mode 100644 index 00000000000..9b4ef993619 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/MarshallingView.java @@ -0,0 +1,134 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.support; + +import java.io.ByteArrayOutputStream; +import java.util.Map; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.stream.StreamResult; + +import org.springframework.beans.BeansException; +import org.springframework.oxm.Marshaller; +import org.springframework.util.Assert; +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.view.AbstractUrlBasedView; + +/** + * Spring-MVC {@link View} that allows for response context to be rendered as the result of marshalling by a {@link + * Marshaller}. + *

+ * The Object to be marshalled is supplied as a parameter in the model and then {@linkplain #locateToBeMarshalled(Map) + * detected} during response rendering. Users can either specify a specific entry in the model via the {@link + * #setModelKey(String) sourceKey} property or have Spring locate the Source object. + * + * @author Arjen Poutsma + * @since 1.5.1 + */ +public class MarshallingView extends AbstractUrlBasedView { + + /** Default content type. Overridable as bean property. */ + public static final String DEFAULT_CONTENT_TYPE = "application/xml"; + + private Marshaller marshaller; + + private String modelKey; + + /** + * Constructs a new MarshallingView with no {@link Marshaller} set. The marshaller must be set after + * construction by invoking {@link #setMarshaller(Marshaller)}. + */ + public MarshallingView() { + setContentType(DEFAULT_CONTENT_TYPE); + } + + /** Constructs a new MarshallingView with the given {@link Marshaller} set. */ + public MarshallingView(Marshaller marshaller) { + Assert.notNull(marshaller, "'marshaller' must not be null"); + setContentType(DEFAULT_CONTENT_TYPE); + this.marshaller = marshaller; + } + + /** Sets the {@link Marshaller} to be used by this view. */ + public void setMarshaller(Marshaller marshaller) { + Assert.notNull(marshaller, "'marshaller' must not be null"); + this.marshaller = marshaller; + } + + /** + * Set the name of the model key that represents the object to be marshalled. If not specified, the model map will + * be searched for a supported value type. + * + * @see Marshaller#supports(Class) + */ + public void setModelKey(String modelKey) { + this.modelKey = modelKey; + } + + @Override + protected void initApplicationContext() throws BeansException { + Assert.notNull(marshaller, "Property 'marshaller' is required"); + } + + @Override + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) + throws Exception { + Object toBeMarshalled = locateToBeMarshalled(model); + if (toBeMarshalled == null) { + throw new ServletException("Unable to locate object to be marshalled in model: " + model); + } + ByteArrayOutputStream bos = new ByteArrayOutputStream(2048); + marshaller.marshal(toBeMarshalled, new StreamResult(bos)); + + response.setContentType(getContentType()); + response.setContentLength(bos.size()); + + ServletOutputStream out = response.getOutputStream(); + bos.writeTo(out); + out.flush(); + } + + /** + * Locates the object to be marshalled. The default implementation first attempts to look under the configured + * {@linkplain #setModelKey(String) model key}, if any, before attempting to locate an object of {@linkplain + * Marshaller#supports(Class) supported type}. + * + * @param model the model Map + * @return the Object to be marshalled (or null if none found) + * @throws ServletException if the model object specified by the {@linkplain #setModelKey(String) model key} is not + * supported by the marshaller + * @see #setModelKey(String) + */ + protected Object locateToBeMarshalled(Map model) throws ServletException { + if (this.modelKey != null) { + Object o = model.get(this.modelKey); + if (!this.marshaller.supports(o.getClass())) { + throw new ServletException("Model object [" + o + "] retrieved via key [" + modelKey + + "] is not supported by the Marshaller"); + } + return o; + } + for (Object o : model.values()) { + if (this.marshaller.supports(o.getClass())) { + return o; + } + } + return null; + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/support/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/package.html new file mode 100644 index 00000000000..2ac6375fe60 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/package.html @@ -0,0 +1,7 @@ + + +Provides generic support classes for using Spring's O/X Mapping integration within various scenario's. Includes the +MarshallingSource for compatibility with TrAX, MarshallingView for use withing Spring Web MVC, and the +MarshallingMessageConverter for use within Spring's JMS support. + + \ No newline at end of file diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java new file mode 100644 index 00000000000..c915ccbc947 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java @@ -0,0 +1,257 @@ +package org.springframework.oxm.xmlbeans; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.xmlbeans.XmlError; +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlObject; +import org.apache.xmlbeans.XmlOptions; +import org.apache.xmlbeans.XmlSaxHandler; +import org.apache.xmlbeans.XmlValidationError; +import org.springframework.oxm.AbstractMarshaller; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.XmlMappingException; +import org.springframework.xml.stream.StaxEventContentHandler; +import org.springframework.xml.stream.StaxEventXmlReader; +import org.springframework.xml.stream.StaxStreamContentHandler; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; + +/** + * Implementation of the {@link Marshaller} interface for XMLBeans. Further options can be set by setting the + * xmlOptions property. The {@link XmlOptionsFactoryBean} is provided to easily wire up {@link XmlOptions} + * instances. + *

+ * Unmarshalled objects can be validated by setting the validating property, or by calling the {@link + * #validate(XmlObject)} method directly. Invalid objects will result in an {@link XmlBeansValidationFailureException}. + *

+ * Note that due to the nature of XMLBeans, this marshaller requires all passed objects to be of type + * {@link XmlObject}. + * + * @author Arjen Poutsma + * @see #setXmlOptions(org.apache.xmlbeans.XmlOptions) + * @see XmlOptionsFactoryBean + * @see #setValidating(boolean) + * @since 1.0.0 + */ +public class XmlBeansMarshaller extends AbstractMarshaller { + + private XmlOptions xmlOptions; + + private boolean validating = false; + + /** Returns the XmlOptions. */ + public XmlOptions getXmlOptions() { + return xmlOptions; + } + + /** + * Sets the XmlOptions. + * + * @see XmlOptionsFactoryBean + */ + public void setXmlOptions(XmlOptions xmlOptions) { + this.xmlOptions = xmlOptions; + } + + /** Returns whether this marshaller should validate in- and outgoing documents. */ + public boolean isValidating() { + return validating; + } + + /** Sets whether this marshaller should validate in- and outgoing documents. Default is false. */ + public void setValidating(boolean validating) { + this.validating = validating; + } + + /** Returns true if the given class is an implementation of {@link XmlObject}. */ + public boolean supports(Class clazz) { + return XmlObject.class.isAssignableFrom(clazz); + } + + protected final void marshalDomNode(Object graph, Node node) throws XmlMappingException { + Document document = node.getNodeType() == Node.DOCUMENT_NODE ? (Document) node : node.getOwnerDocument(); + Node xmlBeansNode = ((XmlObject) graph).newDomNode(getXmlOptions()); + NodeList xmlBeansChildNodes = xmlBeansNode.getChildNodes(); + for (int i = 0; i < xmlBeansChildNodes.getLength(); i++) { + Node xmlBeansChildNode = xmlBeansChildNodes.item(i); + Node importedNode = document.importNode(xmlBeansChildNode, true); + node.appendChild(importedNode); + } + } + + protected final void marshalOutputStream(Object graph, OutputStream outputStream) + throws XmlMappingException, IOException { + ((XmlObject) graph).save(outputStream, getXmlOptions()); + } + + protected final void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler) + throws XmlMappingException { + try { + ((XmlObject) graph).save(contentHandler, lexicalHandler, getXmlOptions()); + } + catch (SAXException ex) { + throw convertXmlBeansException(ex, true); + } + } + + protected final void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException { + ((XmlObject) graph).save(writer, getXmlOptions()); + } + + protected final void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) { + ContentHandler contentHandler = new StaxEventContentHandler(eventWriter); + marshalSaxHandlers(graph, contentHandler, null); + } + + protected final void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException { + ContentHandler contentHandler = new StaxStreamContentHandler(streamWriter); + marshalSaxHandlers(graph, contentHandler, null); + } + + protected final Object unmarshalDomNode(Node node) throws XmlMappingException { + try { + XmlObject object = XmlObject.Factory.parse(node, getXmlOptions()); + validate(object); + return object; + } + catch (XmlException ex) { + throw convertXmlBeansException(ex, false); + } + } + + protected final Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException { + try { + XmlObject object = XmlObject.Factory.parse(inputStream, getXmlOptions()); + validate(object); + return object; + } + catch (XmlException ex) { + throw convertXmlBeansException(ex, false); + } + } + + protected final Object unmarshalReader(Reader reader) throws XmlMappingException, IOException { + try { + XmlObject object = XmlObject.Factory.parse(reader, getXmlOptions()); + validate(object); + return object; + } + catch (XmlException ex) { + throw convertXmlBeansException(ex, false); + } + } + + protected final Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) + throws XmlMappingException, IOException { + XmlSaxHandler saxHandler = XmlObject.Factory.newXmlSaxHandler(getXmlOptions()); + xmlReader.setContentHandler(saxHandler.getContentHandler()); + try { + xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", saxHandler.getLexicalHandler()); + } + catch (SAXNotRecognizedException e) { + // ignore + } + catch (SAXNotSupportedException e) { + // ignore + } + try { + xmlReader.parse(inputSource); + XmlObject object = saxHandler.getObject(); + validate(object); + return object; + } + catch (SAXException ex) { + throw convertXmlBeansException(ex, false); + } + catch (XmlException ex) { + throw convertXmlBeansException(ex, false); + } + } + + protected final Object unmarshalXmlEventReader(XMLEventReader eventReader) throws XmlMappingException { + XMLReader reader = new StaxEventXmlReader(eventReader); + try { + return unmarshalSaxReader(reader, new InputSource()); + } + catch (IOException ex) { + throw convertXmlBeansException(ex, false); + } + } + + protected final Object unmarshalXmlStreamReader(XMLStreamReader streamReader) throws XmlMappingException { + try { + XmlObject object = XmlObject.Factory.parse(streamReader, getXmlOptions()); + validate(object); + return object; + } + catch (XmlException ex) { + throw convertXmlBeansException(ex, false); + } + } + + /** + * Converts the given XMLBeans exception to an appropriate exception from the org.springframework.oxm + * hierarchy. + *

+ * The default implementation delegates to XmlBeansUtils. Can be overridden in subclasses. + *

+ * A boolean flag is used to indicate whether this exception occurs during marshalling or unmarshalling, since + * XMLBeans itself does not make this distinction in its exception hierarchy. + * + * @param ex XMLBeans Exception that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException + * @see XmlBeansUtils#convertXmlBeansException(Exception,boolean) + */ + public XmlMappingException convertXmlBeansException(Exception ex, boolean marshalling) { + return XmlBeansUtils.convertXmlBeansException(ex, marshalling); + } + + /** + * Validates the given XmlObject. + * + * @param object the xml object to validate + * @throws XmlBeansValidationFailureException + * if the given object is not valid + */ + public void validate(XmlObject object) throws XmlBeansValidationFailureException { + if (isValidating() && object != null) { + // create a temporary xmlOptions just for validation + XmlOptions validateOptions = getXmlOptions() != null ? getXmlOptions() : new XmlOptions(); + List errorsList = new ArrayList(); + validateOptions.setErrorListener(errorsList); + if (!object.validate(validateOptions)) { + StringBuffer buffer = new StringBuffer("Could not validate XmlObject :"); + for (Iterator iterator = errorsList.iterator(); iterator.hasNext();) { + XmlError xmlError = (XmlError) iterator.next(); + if (xmlError instanceof XmlValidationError) { + buffer.append(xmlError.toString()); + } + } + XmlException ex = new XmlException(buffer.toString(), null, errorsList); + throw new XmlBeansValidationFailureException(ex); + } + } + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallingFailureException.java new file mode 100644 index 00000000000..1f205d75bd7 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallingFailureException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import org.apache.xmlbeans.XmlException; +import org.springframework.oxm.MarshallingFailureException; +import org.xml.sax.SAXException; + +/** + * XMLBeans-specific subclass of MarshallingFailureException. + * + * @author Arjen Poutsma + * @see XmlBeansUtils#convertXmlBeansException(Exception,boolean) + * @since 1.0.0 + */ +public class XmlBeansMarshallingFailureException extends MarshallingFailureException { + + public XmlBeansMarshallingFailureException(XmlException ex) { + super("XMLBeans marshalling exception: " + ex.getMessage(), ex); + } + + public XmlBeansMarshallingFailureException(SAXException ex) { + super("XMLBeans marshalling exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansSystemException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansSystemException.java new file mode 100644 index 00000000000..7288e745922 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansSystemException.java @@ -0,0 +1,33 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import org.springframework.oxm.UncategorizedXmlMappingException; + +/** + * XMLBeans-specific subclass of UncategorizedXmlMappingException, for XMLBeans exceptions that cannot be + * distinguished further. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class XmlBeansSystemException extends UncategorizedXmlMappingException { + + public XmlBeansSystemException(Exception e) { + super(e.getMessage(), e); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallingFailureException.java new file mode 100644 index 00000000000..6393462f613 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallingFailureException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import org.apache.xmlbeans.XmlException; +import org.springframework.oxm.UnmarshallingFailureException; +import org.xml.sax.SAXException; + +/** + * XMLBeans-specific subclass of UnmarshallingFailureException. + * + * @author Arjen Poutsma + * @see XmlBeansUtils#convertXmlBeansException(Exception,boolean) + * @since 1.0.0 + */ +public class XmlBeansUnmarshallingFailureException extends UnmarshallingFailureException { + + public XmlBeansUnmarshallingFailureException(XmlException ex) { + super("XMLBeans unmarshalling exception: " + ex.getMessage(), ex); + } + + public XmlBeansUnmarshallingFailureException(SAXException ex) { + super("XMLBeans unmarshalling exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUtils.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUtils.java new file mode 100644 index 00000000000..3f78442ad0a --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansUtils.java @@ -0,0 +1,69 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import org.apache.xmlbeans.XMLStreamValidationException; +import org.apache.xmlbeans.XmlException; +import org.springframework.oxm.XmlMappingException; +import org.xml.sax.SAXException; + +/** + * Generic utility methods for working with XMLBeans. Mainly for internal use within the framework. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class XmlBeansUtils { + + /** + * Converts the given XMLBeans exception to an appropriate exception from the org.springframework.oxm + * hierarchy. + *

+ * A boolean flag is used to indicate whether this exception occurs during marshalling or unmarshalling, since + * XMLBeans itself does not make this distinction in its exception hierarchy. + * + * @param ex XMLBeans Exception that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException + */ + public static XmlMappingException convertXmlBeansException(Exception ex, boolean marshalling) { + if (ex instanceof XMLStreamValidationException) { + return new XmlBeansValidationFailureException((XMLStreamValidationException) ex); + } + else if (ex instanceof XmlException) { + XmlException xmlException = (XmlException) ex; + if (marshalling) { + return new XmlBeansMarshallingFailureException(xmlException); + } + else { + return new XmlBeansUnmarshallingFailureException(xmlException); + } + } + else if (ex instanceof SAXException) { + SAXException saxException = (SAXException) ex; + if (marshalling) { + return new XmlBeansMarshallingFailureException(saxException); + } + else { + return new XmlBeansUnmarshallingFailureException(saxException); + } + } + // fallback + return new XmlBeansSystemException(ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansValidationFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansValidationFailureException.java new file mode 100644 index 00000000000..346b7bc8984 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansValidationFailureException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import org.apache.xmlbeans.XMLStreamValidationException; +import org.apache.xmlbeans.XmlException; +import org.springframework.oxm.ValidationFailureException; + +/** + * XMLBeans-specific subclass of ValidationFailureException. + * + * @author Arjen Poutsma + * @see org.springframework.oxm.xmlbeans.XmlBeansUtils#convertXmlBeansException + * @since 1.0.0 + */ +public class XmlBeansValidationFailureException extends ValidationFailureException { + + public XmlBeansValidationFailureException(XMLStreamValidationException ex) { + super("XmlBeans validation exception: " + ex.getMessage(), ex); + } + + public XmlBeansValidationFailureException(XmlException ex) { + super("XmlBeans validation exception: " + ex.getMessage(), ex); + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBean.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBean.java new file mode 100644 index 00000000000..9322303146c --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBean.java @@ -0,0 +1,79 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xmlbeans; + +import java.util.Iterator; +import java.util.Map; + +import org.apache.xmlbeans.XmlOptions; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; + +/** + * Factory bean that configures an XMLBeans XmlOptions object and provides it as a bean reference. + *

+ * Typical usage will be to set XMLBeans options on this bean, and refer to it in the XmlBeansMarshaller. + * + * @author Arjen Poutsma + * @see XmlOptions + * @see #setOptions(java.util.Map) + * @see XmlBeansMarshaller#setXmlOptions(org.apache.xmlbeans.XmlOptions) + * @since 1.0.0 + */ +public class XmlOptionsFactoryBean implements FactoryBean, InitializingBean { + + private XmlOptions xmlOptions; + + private Map options; + + /** Returns the singleton XmlOptions. */ + public Object getObject() throws Exception { + return xmlOptions; + } + + /** Returns the class of XmlOptions. */ + public Class getObjectType() { + return XmlOptions.class; + } + + /** Returns true. */ + public boolean isSingleton() { + return true; + } + + /** + * Sets options on the underlying XmlOptions object. The keys of the supplied map should be one of the + * string constants defined in XmlOptions, the values vary per option. + * + * @see XmlOptions#put(Object,Object) + * @see XmlOptions#SAVE_PRETTY_PRINT + * @see XmlOptions#LOAD_STRIP_COMMENTS + */ + public void setOptions(Map options) { + this.options = options; + } + + public void afterPropertiesSet() throws Exception { + xmlOptions = new XmlOptions(); + if (options != null) { + for (Iterator iterator = options.keySet().iterator(); iterator.hasNext();) { + Object option = iterator.next(); + xmlOptions.put(option, options.get(option)); + } + } + } +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/package.html new file mode 100644 index 00000000000..799fd625853 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/package.html @@ -0,0 +1,5 @@ + + +Package providing integration of XMLBeans with Springs O/X Mapping support. + + diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/AnnotationXStreamMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/AnnotationXStreamMarshaller.java new file mode 100644 index 00000000000..6fa2452bd57 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/AnnotationXStreamMarshaller.java @@ -0,0 +1,53 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.Annotations; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import org.springframework.util.Assert; + +/** + * Subclass of the {@link XStreamMarshaller} that supports JDK 1.5+ annotation metadata for aliases. + * + * @author Arjen Poutsma + * @see XStreamAlias + * @since 1.0.2 + */ +public class AnnotationXStreamMarshaller extends XStreamMarshaller { + + /** + * Sets the classes, for which mappings will be read from class-level JDK 1.5+ annotation metadata. + * + * @see Annotations#configureAliases(XStream, Class[]) + */ + public void setAnnotatedClass(Class annotatedClass) { + Assert.notNull(annotatedClass, "'annotatedClass' must not be null"); + Annotations.configureAliases(getXStream(), annotatedClass); + } + + /** + * Sets annotated classes, for which aliases will be read from class-level JDK 1.5+ annotation metadata. + * + * @see Annotations#configureAliases(XStream, Class[]) + */ + public void setAnnotatedClasses(Class[] annotatedClasses) { + Assert.notEmpty(annotatedClasses, "'annotatedClasses' must not be empty"); + Annotations.configureAliases(getXStream(), annotatedClasses); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java new file mode 100644 index 00000000000..839fa2c7cd7 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java @@ -0,0 +1,461 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.Iterator; +import java.util.Map; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterMatcher; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.xml.CompactWriter; +import com.thoughtworks.xstream.io.xml.DomReader; +import com.thoughtworks.xstream.io.xml.DomWriter; +import com.thoughtworks.xstream.io.xml.QNameMap; +import com.thoughtworks.xstream.io.xml.SaxWriter; +import com.thoughtworks.xstream.io.xml.StaxReader; +import com.thoughtworks.xstream.io.xml.StaxWriter; +import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer; +import com.thoughtworks.xstream.io.xml.XppReader; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; + +import org.springframework.beans.propertyeditors.ClassEditor; +import org.springframework.oxm.AbstractMarshaller; +import org.springframework.oxm.XmlMappingException; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.xml.stream.StaxEventContentHandler; +import org.springframework.xml.stream.XmlEventStreamReader; + +/** + * Implementation of the Marshaller interface for XStream. By default, XStream does not require any further + * configuration, though class aliases can be used to have more control over the behavior of XStream. + *

+ * Due to XStream's API, it is required to set the encoding used for writing to outputstreams. It defaults to + * UTF-8. + *

+ * Note that XStream is an XML serialization library, not a data binding library. Therefore, it has limited + * namespace support. As such, it is rather unsuitable for usage within Web services. + * + * @author Peter Meijer + * @author Arjen Poutsma + * @see #setEncoding(String) + * @see #DEFAULT_ENCODING + * @see #setAliases(Map) + * @see #setConverters(ConverterMatcher[]) + * @since 1.0.0 + */ +public class XStreamMarshaller extends AbstractMarshaller { + + /** The default encoding used for stream access. */ + public static final String DEFAULT_ENCODING = "UTF-8"; + + private XStream xstream = new XStream(); + + private String encoding; + + private Class[] supportedClasses; + + /** Specialized driver to be used with stream readers and writers */ + private HierarchicalStreamDriver streamDriver; + + /** + * Returns the encoding to be used for stream access. If this property is not set, the default encoding is used. + * + * @see #DEFAULT_ENCODING + */ + public String getEncoding() { + return encoding != null ? encoding : DEFAULT_ENCODING; + } + + /** + * Sets the encoding to be used for stream access. If this property is not set, the default encoding is used. + * + * @see #DEFAULT_ENCODING + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** Returns the XStream instance used by this marshaller. */ + public XStream getXStream() { + return xstream; + } + + /** + * Sets the XStream mode. + * + * @see XStream#XPATH_REFERENCES + * @see XStream#ID_REFERENCES + * @see XStream#NO_REFERENCES + */ + public void setMode(int mode) { + getXStream().setMode(mode); + } + + /** + * Sets the classes supported by this marshaller. If this property is empty (the default), all classes are + * supported. + * + * @see #supports(Class) + */ + public void setSupportedClasses(Class[] supportedClasses) { + this.supportedClasses = supportedClasses; + } + + /** + * Sets the Converters or SingleValueConverters to be registered with the + * XStream instance. + * + * @see Converter + * @see SingleValueConverter + */ + public void setConverters(ConverterMatcher[] converters) { + for (int i = 0; i < converters.length; i++) { + if (converters[i] instanceof Converter) { + getXStream().registerConverter((Converter) converters[i], i); + } + else if (converters[i] instanceof SingleValueConverter) { + getXStream().registerConverter((SingleValueConverter) converters[i], i); + } + else { + throw new IllegalArgumentException("Invalid ConverterMatcher [" + converters[i] + "]"); + } + } + } + + /** Sets the XStream hierarchical stream driver to be used with stream readers and writers */ + public void setStreamDriver(HierarchicalStreamDriver streamDriver) { + this.streamDriver = streamDriver; + } + + /** + * Set a alias/type map, consisting of string aliases mapped to Class instances (or Strings to be + * converted to Class instances). + * + * @see org.springframework.beans.propertyeditors.ClassEditor + */ + public void setAliases(Map aliases) { + for (Iterator iterator = aliases.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + // Check whether we need to convert from String to Class. + Class type; + if (entry.getValue() instanceof Class) { + type = (Class) entry.getValue(); + } + else { + ClassEditor editor = new ClassEditor(); + editor.setAsText(String.valueOf(entry.getValue())); + type = (Class) editor.getValue(); + } + addAlias((String) entry.getKey(), type); + } + } + + /** + * Adds an alias for the given type. + * + * @param name alias to be used for the type + * @param type the type to be aliased + */ + public void addAlias(String name, Class type) { + getXStream().alias(name, type); + } + + /** + * Sets types to use XML attributes for. + * + * @see XStream#useAttributeFor(Class) + */ + public void setUseAttributeForTypes(Class[] types) { + for (int i = 0; i < types.length; i++) { + getXStream().useAttributeFor(types[i]); + } + } + + /** + * Sets the types to use XML attributes for. The given map can contain either <String, Class> + * pairs, in which case {@link XStream#useAttributeFor(String,Class)} is called, or <Class, + * String> pairs, which results in {@link XStream#useAttributeFor(Class,String)}. + */ + public void setUseAttributeFor(Map attributes) { + for (Iterator iterator = attributes.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + if (entry.getKey() instanceof String && entry.getValue() instanceof Class) { + getXStream().useAttributeFor((String) entry.getKey(), (Class) entry.getValue()); + } + else if (entry.getKey() instanceof Class && entry.getValue() instanceof String) { + getXStream().useAttributeFor((Class) entry.getKey(), (String) entry.getValue()); + } + else { + throw new IllegalArgumentException("Invalid attribute key and value pair. " + + "'useAttributesFor' property takes either a map or a map"); + } + } + } + + /** + * Adds an implicit Collection for the given type. + * + * @see XStream#addImplicitCollection(Class, String) + */ + public void addImplicitCollection(String name, Class type) { + getXStream().addImplicitCollection(type, name); + } + + /** + * Set a implicit colletion/type map, consisting of string implicit collection mapped to Class + * instances (or Strings to be converted to Class instances). + * + * @see XStream#addImplicitCollection(Class, String) + */ + public void setImplicitCollection(Map implicitCollection) { + for (Iterator iterator = implicitCollection.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + // Check whether we need to convert from String to Class. + Class type; + if (entry.getValue() instanceof Class) { + type = (Class) entry.getValue(); + } + else { + ClassEditor editor = new ClassEditor(); + editor.setAsText(String.valueOf(entry.getValue())); + type = (Class) editor.getValue(); + } + addImplicitCollection((String) entry.getKey(), type); + } + } + + /** + * Adds an omitted field for the given type. + * + * @param type the type to be containing the field + * @param fieldName field to omitt + * @see XStream#omitField(Class, String) + */ + public void addOmittedField(Class type, String fieldName) { + getXStream().omitField(type, fieldName); + } + + /** + * Sets a ommited field map, consisting of Class instances (or Strings to be converted to + * Class instances) mapped to comma separated field names. + * + * @see XStream#omitField(Class, String) + */ + public void setOmittedFields(Map omittedFields) { + for (Iterator iterator = omittedFields.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + // Check whether we need to convert from String to Class. + Class type; + if (entry.getKey() instanceof Class) { + type = (Class) entry.getKey(); + } + else { + ClassEditor editor = new ClassEditor(); + editor.setAsText(String.valueOf(entry.getKey())); + type = (Class) editor.getValue(); + } + // add each omitted field for the current type + String fieldsString = (String) entry.getValue(); + String[] fields = StringUtils.commaDelimitedListToStringArray(fieldsString); + for (int i = 0; i < fields.length; i++) { + addOmittedField(type, fields[i]); + } + } + } + + public boolean supports(Class clazz) { + if (ObjectUtils.isEmpty(supportedClasses)) { + return true; + } + else { + for (int i = 0; i < supportedClasses.length; i++) { + if (supportedClasses[i].isAssignableFrom(clazz)) { + return true; + } + } + return false; + } + } + + /** + * Convert the given XStream exception to an appropriate exception from the org.springframework.oxm + * hierarchy. + *

+ * The default implementation delegates to XStreamUtils. Can be overridden in subclasses. + * + * @param ex exception that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException instance + * @see XStreamUtils#convertXStreamException(Exception,boolean) + */ + public XmlMappingException convertXStreamException(Exception ex, boolean marshalling) { + return XStreamUtils.convertXStreamException(ex, marshalling); + } + + // + // Marshalling + // + + /** + * Marshals the given graph to the given XStream HierarchicalStreamWriter. Converts exceptions using + * convertXStreamException. + */ + private void marshal(Object graph, HierarchicalStreamWriter streamWriter) { + try { + getXStream().marshal(graph, streamWriter); + } + catch (Exception ex) { + throw convertXStreamException(ex, true); + } + } + + protected void marshalDomNode(Object graph, Node node) throws XmlMappingException { + HierarchicalStreamWriter streamWriter; + if (node instanceof Document) { + streamWriter = new DomWriter((Document) node); + } + else if (node instanceof Element) { + streamWriter = new DomWriter((Element) node, node.getOwnerDocument(), new XmlFriendlyReplacer()); + } + else { + throw new IllegalArgumentException("DOMResult contains neither Document nor Element"); + } + marshal(graph, streamWriter); + } + + protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException { + ContentHandler contentHandler = new StaxEventContentHandler(eventWriter); + marshalSaxHandlers(graph, contentHandler, null); + } + + protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException { + try { + marshal(graph, new StaxWriter(new QNameMap(), streamWriter)); + } + catch (XMLStreamException ex) { + throw convertXStreamException(ex, true); + } + } + + protected void marshalOutputStream(Object graph, OutputStream outputStream) + throws XmlMappingException, IOException { + marshalWriter(graph, new OutputStreamWriter(outputStream, getEncoding())); + } + + protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler) + throws XmlMappingException { + SaxWriter saxWriter = new SaxWriter(); + saxWriter.setContentHandler(contentHandler); + marshal(graph, saxWriter); + } + + protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException { + if (streamDriver != null) { + marshal(graph, streamDriver.createWriter(writer)); + } + else { + marshal(graph, new CompactWriter(writer)); + } + } + + // + // Unmarshalling + // + + private Object unmarshal(HierarchicalStreamReader streamReader) { + try { + return getXStream().unmarshal(streamReader); + } + catch (Exception ex) { + throw convertXStreamException(ex, false); + } + } + + protected Object unmarshalDomNode(Node node) throws XmlMappingException { + HierarchicalStreamReader streamReader; + if (node instanceof Document) { + streamReader = new DomReader((Document) node); + } + else if (node instanceof Element) { + streamReader = new DomReader((Element) node); + } + else { + throw new IllegalArgumentException("DOMSource contains neither Document nor Element"); + } + return unmarshal(streamReader); + } + + protected Object unmarshalXmlEventReader(XMLEventReader eventReader) throws XmlMappingException { + try { + XMLStreamReader streamReader = new XmlEventStreamReader(eventReader); + return unmarshalXmlStreamReader(streamReader); + } + catch (XMLStreamException ex) { + throw convertXStreamException(ex, false); + } + } + + protected Object unmarshalXmlStreamReader(XMLStreamReader streamReader) throws XmlMappingException { + return unmarshal(new StaxReader(new QNameMap(), streamReader)); + } + + protected Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException { + return unmarshalReader(new InputStreamReader(inputStream, getEncoding())); + } + + protected Object unmarshalReader(Reader reader) throws XmlMappingException, IOException { + if (streamDriver != null) { + return unmarshal(streamDriver.createReader(reader)); + } + else { + return unmarshal(new XppReader(reader)); + } + } + + protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) + throws XmlMappingException, IOException { + throw new UnsupportedOperationException( + "XStreamMarshaller does not support unmarshalling using SAX XMLReaders"); + } + + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshallingFailureException.java new file mode 100644 index 00000000000..931d0068753 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshallingFailureException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import com.thoughtworks.xstream.alias.CannotResolveClassException; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.io.StreamException; +import org.springframework.oxm.MarshallingFailureException; + +/** + * XStream-specific subclass of MarshallingFailureException. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class XStreamMarshallingFailureException extends MarshallingFailureException { + + public XStreamMarshallingFailureException(String msg) { + super(msg); + } + + public XStreamMarshallingFailureException(StreamException ex) { + super("XStream marshalling exception: " + ex.getMessage(), ex); + + } + + public XStreamMarshallingFailureException(CannotResolveClassException ex) { + super("XStream resolving exception: " + ex.getMessage(), ex); + } + + public XStreamMarshallingFailureException(ConversionException ex) { + super("XStream conversion exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamSystemException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamSystemException.java new file mode 100644 index 00000000000..a4e48a0bb97 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamSystemException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import org.springframework.oxm.UncategorizedXmlMappingException; + +/** + * XStream-specific subclass of UncategorizedXmlMappingException, for XStream exceptions that cannot be + * distinguished further. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class XStreamSystemException extends UncategorizedXmlMappingException { + + public XStreamSystemException(String msg, Throwable ex) { + super(msg, ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUnmarshallingFailureException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUnmarshallingFailureException.java new file mode 100644 index 00000000000..e293c9029d2 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUnmarshallingFailureException.java @@ -0,0 +1,54 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import javax.xml.stream.XMLStreamException; + +import com.thoughtworks.xstream.alias.CannotResolveClassException; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.io.StreamException; +import org.springframework.oxm.UnmarshallingFailureException; + +/** + * XStream-specific subclass of UnmarshallingFailureException. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public class XStreamUnmarshallingFailureException extends UnmarshallingFailureException { + + public XStreamUnmarshallingFailureException(StreamException ex) { + super("XStream unmarshalling exception: " + ex.getMessage(), ex); + } + + public XStreamUnmarshallingFailureException(CannotResolveClassException ex) { + super("XStream resolving exception: " + ex.getMessage(), ex); + } + + public XStreamUnmarshallingFailureException(ConversionException ex) { + super("XStream conversion exception: " + ex.getMessage(), ex); + } + + public XStreamUnmarshallingFailureException(String msg) { + super(msg); + } + + public XStreamUnmarshallingFailureException(String msg, XMLStreamException ex) { + super(msg, ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUtils.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUtils.java new file mode 100644 index 00000000000..929a66263a4 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamUtils.java @@ -0,0 +1,73 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import com.thoughtworks.xstream.alias.CannotResolveClassException; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.io.StreamException; +import org.springframework.oxm.XmlMappingException; + +/** + * Generic utility methods for working with XStream. Mainly for internal use within the framework. + * + * @author Arjen Poutsma + * @since 1.0.0 + */ +public abstract class XStreamUtils { + + /** + * Converts the given XStream exception to an appropriate exception from the org.springframework.oxm + * hierarchy. + *

+ * A boolean flag is used to indicate whether this exception occurs during marshalling or unmarshalling, since + * XStream itself does not make this distinction in its exception hierarchy. + * + * @param ex XStream exception that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or + * unmarshalling (false) + * @return the corresponding XmlMappingException + */ + public static XmlMappingException convertXStreamException(Exception ex, boolean marshalling) { + if (ex instanceof StreamException) { + if (marshalling) { + return new XStreamMarshallingFailureException((StreamException) ex); + } + else { + return new XStreamUnmarshallingFailureException((StreamException) ex); + } + } + else if (ex instanceof CannotResolveClassException) { + if (marshalling) { + return new XStreamMarshallingFailureException((CannotResolveClassException) ex); + } + else { + return new XStreamUnmarshallingFailureException((CannotResolveClassException) ex); + } + } + else if (ex instanceof ConversionException) { + if (marshalling) { + return new XStreamMarshallingFailureException((ConversionException) ex); + } + else { + return new XStreamUnmarshallingFailureException((ConversionException) ex); + } + } + // fallback + return new XStreamSystemException("Unknown XStream exception: " + ex.getMessage(), ex); + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/package.html b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/package.html new file mode 100644 index 00000000000..ab174437f97 --- /dev/null +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/package.html @@ -0,0 +1,5 @@ + + +Package providing integration of XStream with Springs O/X Mapping support. + + diff --git a/org.springframework.oxm/src/main/resources/META-INF/spring.handlers b/org.springframework.oxm/src/main/resources/META-INF/spring.handlers new file mode 100644 index 00000000000..22a2a50458b --- /dev/null +++ b/org.springframework.oxm/src/main/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.springframework.org/schema/oxm=org.springframework.oxm.config.OxmNamespaceHandler \ No newline at end of file diff --git a/org.springframework.oxm/src/main/resources/META-INF/spring.schemas b/org.springframework.oxm/src/main/resources/META-INF/spring.schemas new file mode 100644 index 00000000000..43b7186b4f5 --- /dev/null +++ b/org.springframework.oxm/src/main/resources/META-INF/spring.schemas @@ -0,0 +1 @@ +http\://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd=/org/springframework/oxm/config/spring-oxm-1.5.xsd \ No newline at end of file diff --git a/org.springframework.oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-1.5.xsd b/org.springframework.oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-1.5.xsd new file mode 100644 index 00000000000..a81a43a5fde --- /dev/null +++ b/org.springframework.oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-1.5.xsd @@ -0,0 +1,146 @@ + + + + + + + + + Defines the elements used in Spring's Object/XML Mapping integration. + + + + + + + + Defines a JAXB1 Marshaller. + + + + + + + + + + + + The JAXB Context path + + + + + Whether incoming XML should be validated. + + + + + + + + + + + + Defines a JAXB2 Marshaller. + + + + + + + + + + + + + + + + + + + The JAXB Context path + + + + + + + + + + + + Defines a JiBX Marshaller. + + + + + + + + + + + + + The binding name used by this marshaller. + + + + + + + + + + + + Defines a XMLBeans Marshaller. + + + + + + + + + + + + + The bean name of the XmlOptions that is to be used for this marshaller. Typically a + XmlOptionsFactoryBean definition. + + + + + + + + + + + + + + + + A class supported by a marshaller. + + + + + + + + + + diff --git a/org.springframework.oxm/src/test/castor/castorbuilder.properties b/org.springframework.oxm/src/test/castor/castorbuilder.properties new file mode 100644 index 00000000000..e69de29bb2d diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java new file mode 100644 index 00000000000..033ddc83a43 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java @@ -0,0 +1,130 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stax.StAXResult; +import javax.xml.transform.stream.StreamResult; + +import org.custommonkey.xmlunit.XMLTestCase; +import org.custommonkey.xmlunit.XMLUnit; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; + +import org.springframework.xml.transform.StaxResult; + +public abstract class AbstractMarshallerTestCase extends XMLTestCase { + + protected Marshaller marshaller; + + protected Object flights; + + protected static final String EXPECTED_STRING = + "" + + "42"; + + protected final void setUp() throws Exception { + marshaller = createMarshaller(); + flights = createFlights(); + XMLUnit.setIgnoreWhitespace(true); + } + + protected abstract Marshaller createMarshaller() throws Exception; + + protected abstract Object createFlights(); + + public void testMarshalDOMResult() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder(); + Document result = builder.newDocument(); + DOMResult domResult = new DOMResult(result); + marshaller.marshal(flights, domResult); + Document expected = builder.newDocument(); + Element flightsElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:flights"); + Attr namespace = expected.createAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:tns"); + namespace.setNodeValue("http://samples.springframework.org/flight"); + flightsElement.setAttributeNode(namespace); + expected.appendChild(flightsElement); + Element flightElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:flight"); + flightsElement.appendChild(flightElement); + Element numberElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:number"); + flightElement.appendChild(numberElement); + Text text = expected.createTextNode("42"); + numberElement.appendChild(text); + assertXMLEqual("Marshaller writes invalid DOMResult", expected, result); + } + + public void testMarshalStreamResultWriter() throws Exception { + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStreamResultOutputStream() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + StreamResult result = new StreamResult(os); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, + new String(os.toByteArray(), "UTF-8")); + } + + public void testMarshalStaxResultStreamWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer); + StaxResult result = new StaxResult(streamWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStaxResultEventWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer); + StaxResult result = new StaxResult(eventWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalJaxp14StaxResultStreamWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer); + StAXResult result = new StAXResult(streamWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalJaxp14StaxResultEventWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer); + StAXResult result = new StAXResult(eventWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractUnmarshallerTestCase.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractUnmarshallerTestCase.java new file mode 100644 index 00000000000..a9b0a665ab3 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/AbstractUnmarshallerTestCase.java @@ -0,0 +1,139 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm; + +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; +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 junit.framework.TestCase; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import org.springframework.xml.transform.StaxSource; + +public abstract class AbstractUnmarshallerTestCase extends TestCase { + + protected Unmarshaller unmarshaller; + + protected static final String INPUT_STRING = + "" + + "42"; + + protected final void setUp() throws Exception { + unmarshaller = createUnmarshaller(); + } + + protected abstract Unmarshaller createUnmarshaller() throws Exception; + + protected abstract void testFlights(Object o); + + protected abstract void testFlight(Object o); + + public void testUnmarshalDomSource() throws Exception { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document document = builder.newDocument(); + Element flightsElement = document.createElementNS("http://samples.springframework.org/flight", "tns:flights"); + document.appendChild(flightsElement); + Element flightElement = document.createElementNS("http://samples.springframework.org/flight", "tns:flight"); + flightsElement.appendChild(flightElement); + Element numberElement = document.createElementNS("http://samples.springframework.org/flight", "tns:number"); + flightElement.appendChild(numberElement); + Text text = document.createTextNode("42"); + numberElement.appendChild(text); + DOMSource source = new DOMSource(document); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStreamSourceReader() throws Exception { + StreamSource source = new StreamSource(new StringReader(INPUT_STRING)); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStreamSourceInputStream() throws Exception { + StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes("UTF-8"))); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalSAXSource() throws Exception { + XMLReader reader = XMLReaderFactory.createXMLReader(); + SAXSource source = new SAXSource(reader, new InputSource(new StringReader(INPUT_STRING))); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStaxSourceXmlStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + StaxSource source = new StaxSource(streamReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStaxSourceXmlEventReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(INPUT_STRING)); + StaxSource source = new StaxSource(eventReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalJaxp14StaxSourceXmlStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + StAXSource source = new StAXSource(streamReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalJaxp14StaxSourceXmlEventReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(INPUT_STRING)); + StAXSource source = new StAXSource(eventReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalPartialStaxSourceXmlStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + streamReader.nextTag(); // skip to flights + assertEquals("Invalid element", new QName("http://samples.springframework.org/flight", "flights"), + streamReader.getName()); + streamReader.nextTag(); // skip to flight + assertEquals("Invalid element", new QName("http://samples.springframework.org/flight", "flight"), + streamReader.getName()); + StaxSource source = new StaxSource(streamReader); + Object flight = unmarshaller.unmarshal(source); + testFlight(flight); + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorMarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorMarshallerTest.java new file mode 100644 index 00000000000..893c9ef446a --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorMarshallerTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import javax.xml.transform.sax.SAXResult; + +import org.easymock.MockControl; +import org.springframework.core.io.ClassPathResource; +import org.springframework.oxm.AbstractMarshallerTestCase; +import org.springframework.oxm.Marshaller; +import org.xml.sax.ContentHandler; + +public class CastorMarshallerTest extends AbstractMarshallerTestCase { + + protected Marshaller createMarshaller() throws Exception { + CastorMarshaller marshaller = new CastorMarshaller(); + ClassPathResource mappingLocation = new ClassPathResource("mapping.xml", CastorMarshaller.class); + marshaller.setMappingLocation(mappingLocation); + marshaller.afterPropertiesSet(); + return marshaller; + } + + protected Object createFlights() { + Flight flight = new Flight(); + flight.setNumber(42L); + Flights flights = new Flights(); + flights.addFlight(flight); + return flights; + } + + public void testMarshalSaxResult() throws Exception { + MockControl handlerControl = MockControl.createControl(ContentHandler.class); + ContentHandler handlerMock = (ContentHandler) handlerControl.getMock(); + handlerMock.startDocument(); + handlerMock.startPrefixMapping("tns", "http://samples.springframework.org/flight"); + handlerMock.startElement("http://samples.springframework.org/flight", "flights", "tns:flights", null); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.startElement("http://samples.springframework.org/flight", "flight", "tns:flight", null); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.startElement("http://samples.springframework.org/flight", "number", "tns:number", null); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.characters(new char[]{'4', '2'}, 0, 2); + handlerControl.setMatcher(MockControl.ARRAY_MATCHER); + handlerMock.endElement("http://samples.springframework.org/flight", "number", "tns:number"); + handlerMock.endElement("http://samples.springframework.org/flight", "flight", "tns:flight"); + handlerMock.endElement("http://samples.springframework.org/flight", "flights", "tns:flights"); + handlerMock.endPrefixMapping("tns"); + handlerMock.endDocument(); + + handlerControl.replay(); + SAXResult result = new SAXResult(handlerMock); + marshaller.marshal(flights, result); + handlerControl.verify(); + } + + public void testSupports() throws Exception { + assertTrue("CastorMarshaller does not support Flights", marshaller.supports(Flights.class)); + assertTrue("CastorMarshaller does not support Flight", marshaller.supports(Flight.class)); + } + + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTest.java new file mode 100644 index 00000000000..d271a0aeeaa --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTest.java @@ -0,0 +1,71 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import javax.xml.transform.stream.StreamSource; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.oxm.AbstractUnmarshallerTestCase; +import org.springframework.oxm.Unmarshaller; + +public class CastorUnmarshallerTest extends AbstractUnmarshallerTestCase { + + protected void testFlights(Object o) { + Flights flights = (Flights) o; + assertNotNull("Flights is null", flights); + assertEquals("Invalid amount of flight elements", 1, flights.getFlightCount()); + testFlight(flights.getFlight()[0]); + } + + protected void testFlight(Object o) { + Flight flight = (Flight) o; + assertNotNull("Flight is null", flight); + assertEquals("Number is invalid", 42L, flight.getNumber()); + } + + protected Unmarshaller createUnmarshaller() throws Exception { + CastorMarshaller marshaller = new CastorMarshaller(); + ClassPathResource mappingLocation = new ClassPathResource("mapping.xml", CastorMarshaller.class); + marshaller.setMappingLocation(mappingLocation); + marshaller.afterPropertiesSet(); + return marshaller; + } + + public void testUnmarshalTargetClass() throws Exception { + CastorMarshaller unmarshaller = new CastorMarshaller(); + unmarshaller.setTargetClass(Flights.class); + unmarshaller.afterPropertiesSet(); + StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes("UTF-8"))); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testSetBothTargetClassAndMapping() throws IOException { + try { + CastorMarshaller marshaller = new CastorMarshaller(); + marshaller.setMappingLocation(new ClassPathResource("mapping.xml", CastorMarshaller.class)); + marshaller.setTargetClass(getClass()); + marshaller.afterPropertiesSet(); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUtilsTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUtilsTest.java new file mode 100644 index 00000000000..8f663d0d132 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/castor/CastorUtilsTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.castor; + +import junit.framework.TestCase; +import org.exolab.castor.xml.MarshalException; +import org.exolab.castor.xml.ValidationException; +import org.exolab.castor.xml.XMLException; + +public class CastorUtilsTest extends TestCase { + + public void testConvertMarshalException() { + assertTrue("Invalid exception conversion", CastorUtils + .convertXmlException(new MarshalException(""), true) instanceof CastorMarshallingFailureException); + assertTrue("Invalid exception conversion", CastorUtils + .convertXmlException(new MarshalException(""), false) instanceof CastorUnmarshallingFailureException); + } + + public void testConvertValidationException() { + assertTrue("Invalid exception conversion", CastorUtils + .convertXmlException(new ValidationException(""), false) instanceof CastorValidationFailureException); + } + + public void testConvertXMLException() { + assertTrue("Invalid exception conversion", + CastorUtils.convertXmlException(new XMLException(""), false) instanceof CastorSystemException); + } + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/config/Jaxb2OxmNamespaceHandlerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/config/Jaxb2OxmNamespaceHandlerTest.java new file mode 100644 index 00000000000..c7a4548ea9c --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/config/Jaxb2OxmNamespaceHandlerTest.java @@ -0,0 +1,41 @@ +/* + * Copyright ${YEAR} the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.config; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.oxm.jaxb.Jaxb2Marshaller; + +import junit.framework.TestCase; + +public class Jaxb2OxmNamespaceHandlerTest extends TestCase { + + private ApplicationContext applicationContext; + + protected void setUp() throws Exception { + applicationContext = new ClassPathXmlApplicationContext("jaxb2OxmNamespaceHandlerTest.xml", getClass()); + } + + public void testContextPathMarshaller() throws Exception { + applicationContext.getBean("contextPathMarshaller", Jaxb2Marshaller.class); + } + + public void testClassesToBeBoundMarshaller() throws Exception { + applicationContext.getBean("classesMarshaller", Jaxb2Marshaller.class); + } + +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/config/OxmNamespaceHandlerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/config/OxmNamespaceHandlerTest.java new file mode 100644 index 00000000000..aa81c6ae91e --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/config/OxmNamespaceHandlerTest.java @@ -0,0 +1,52 @@ +/* + * Copyright ${YEAR} the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.config; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.oxm.jaxb.Jaxb1Marshaller; +import org.springframework.oxm.jibx.JibxMarshaller; +import org.springframework.oxm.xmlbeans.XmlBeansMarshaller; + +import junit.framework.TestCase; +import org.apache.xmlbeans.XmlOptions; + +public class OxmNamespaceHandlerTest extends TestCase { + + private ApplicationContext applicationContext; + + protected void setUp() throws Exception { + applicationContext = new ClassPathXmlApplicationContext("oxmNamespaceHandlerTest.xml", getClass()); + } + + public void testJaxb1Marshaller() throws Exception { + applicationContext.getBean("jaxb1Marshaller", Jaxb1Marshaller.class); + } + + public void testJibxMarshaller() throws Exception { + applicationContext.getBean("jibxMarshaller", JibxMarshaller.class); + } + + public void testXmlBeansMarshaller() throws Exception { + XmlBeansMarshaller marshaller = + (XmlBeansMarshaller) applicationContext.getBean("xmlBeansMarshaller", XmlBeansMarshaller.class); + XmlOptions options = marshaller.getXmlOptions(); + assertNotNull("Options not set", options); + assertTrue("option not set", options.hasOption("SAVE_PRETTY_PRINT")); + assertEquals("option not set", "true", options.get("SAVE_PRETTY_PRINT")); + } +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/AbstractJaxbMarshallerTestCase.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/AbstractJaxbMarshallerTestCase.java new file mode 100644 index 00000000000..3e7895463fd --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/AbstractJaxbMarshallerTestCase.java @@ -0,0 +1,56 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jaxb; + +import javax.xml.transform.sax.SAXResult; + +import org.easymock.MockControl; +import org.xml.sax.ContentHandler; + +import org.springframework.oxm.AbstractMarshallerTestCase; + +public abstract class AbstractJaxbMarshallerTestCase extends AbstractMarshallerTestCase { + + public void testMarshalSaxResult() throws Exception { + MockControl handlerControl = MockControl.createStrictControl(ContentHandler.class); + ContentHandler handlerMock = (ContentHandler) handlerControl.getMock(); + handlerMock.setDocumentLocator(null); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.startDocument(); + handlerMock.startPrefixMapping("", "http://samples.springframework.org/flight"); + handlerMock.startElement("http://samples.springframework.org/flight", "flights", "flights", null); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.startElement("http://samples.springframework.org/flight", "flight", "flight", null); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.startElement("http://samples.springframework.org/flight", "number", "number", null); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.characters(new char[]{'4', '2'}, 0, 2); + handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.endElement("http://samples.springframework.org/flight", "number", "number"); + handlerMock.endElement("http://samples.springframework.org/flight", "flight", "flight"); + handlerMock.endElement("http://samples.springframework.org/flight", "flights", "flights"); + handlerMock.endPrefixMapping(""); + handlerMock.endDocument(); + + handlerControl.replay(); + SAXResult result = new SAXResult(handlerMock); + marshaller.marshal(flights, result); + handlerControl.verify(); + } + + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java new file mode 100644 index 00000000000..7f15d0417f3 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java @@ -0,0 +1,57 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jaxb; + +import javax.activation.DataHandler; +import javax.xml.bind.annotation.XmlAttachmentRef; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(namespace = "http://springframework.org/spring-ws") +public class BinaryObject { + + @XmlElement(namespace = "http://springframework.org/spring-ws") + private byte[] bytes; + + @XmlElement(namespace = "http://springframework.org/spring-ws") + private DataHandler dataHandler; + + @XmlElement(namespace = "http://springframework.org/spring-ws") + @XmlAttachmentRef + private DataHandler swaDataHandler; + + public BinaryObject() { + } + + public BinaryObject(byte[] bytes, DataHandler dataHandler) { + this.bytes = bytes; + this.dataHandler = dataHandler; + swaDataHandler = dataHandler; + } + + public byte[] getBytes() { + return bytes; + } + + public DataHandler getDataHandler() { + return dataHandler; + } + + public DataHandler getSwaDataHandler() { + return swaDataHandler; + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1MarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1MarshallerTest.java new file mode 100644 index 00000000000..74e3018ac1d --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1MarshallerTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import java.util.Collections; + +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.XmlMappingException; +import org.springframework.oxm.jaxb1.FlightType; +import org.springframework.oxm.jaxb1.Flights; +import org.springframework.oxm.jaxb1.FlightsType; +import org.springframework.oxm.jaxb1.impl.FlightTypeImpl; +import org.springframework.oxm.jaxb1.impl.FlightsImpl; + +public class Jaxb1MarshallerTest extends AbstractJaxbMarshallerTestCase { + + private static final String CONTEXT_PATH = "org.springframework.oxm.jaxb1"; + + protected final Marshaller createMarshaller() throws Exception { + Jaxb1Marshaller marshaller = new Jaxb1Marshaller(); + marshaller.setContextPaths(new String[]{CONTEXT_PATH}); + marshaller.afterPropertiesSet(); + return marshaller; + } + + protected Object createFlights() { + FlightType flight = new FlightTypeImpl(); + flight.setNumber(42L); + Flights flights = new FlightsImpl(); + flights.getFlight().add(flight); + return flights; + } + + public void testProperties() throws Exception { + Jaxb1Marshaller marshaller = new Jaxb1Marshaller(); + marshaller.setContextPath(CONTEXT_PATH); + marshaller.setMarshallerProperties( + Collections.singletonMap(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE)); + marshaller.afterPropertiesSet(); + } + + public void testNoContextPath() throws Exception { + try { + Jaxb1Marshaller marshaller = new Jaxb1Marshaller(); + marshaller.afterPropertiesSet(); + fail("Should have thrown an IllegalArgumentException"); + } + catch (IllegalArgumentException e) { + } + } + + public void testInvalidContextPath() throws Exception { + try { + Jaxb1Marshaller marshaller = new Jaxb1Marshaller(); + marshaller.setContextPath("ab"); + marshaller.afterPropertiesSet(); + fail("Should have thrown an XmlMappingException"); + } + catch (XmlMappingException ex) { + } + } + + public void testSupports() throws Exception { + assertTrue("Jaxb1Marshaller does not support Flights", marshaller.supports(Flights.class)); + assertFalse("Jaxb1Marshaller supports FlightsType", marshaller.supports(FlightsType.class)); + } + + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1UnmarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1UnmarshallerTest.java new file mode 100644 index 00000000000..692f03141df --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb1UnmarshallerTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import org.springframework.oxm.AbstractUnmarshallerTestCase; +import org.springframework.oxm.Unmarshaller; +import org.springframework.oxm.jaxb1.FlightType; +import org.springframework.oxm.jaxb1.Flights; + +public class Jaxb1UnmarshallerTest extends AbstractUnmarshallerTestCase { + + protected Unmarshaller createUnmarshaller() throws Exception { + Jaxb1Marshaller marshaller = new Jaxb1Marshaller(); + marshaller.setContextPath("org.springframework.oxm.jaxb1"); + marshaller.setValidating(true); + marshaller.afterPropertiesSet(); + return marshaller; + } + + protected void testFlights(Object o) { + Flights flights = (Flights) o; + assertNotNull("Flights is null", flights); + assertEquals("Invalid amount of flight elements", 1, flights.getFlight().size()); + testFlight(flights.getFlight().get(0)); + } + + protected void testFlight(Object o) { + FlightType flight = (FlightType) o; + assertNotNull("Flight is null", flight); + assertEquals("Number is invalid", 42L, flight.getNumber()); + } + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java new file mode 100644 index 00000000000..9172e67d308 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java @@ -0,0 +1,329 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jaxb; + +import java.awt.*; +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.UUID; +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.xml.bind.JAXBElement; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stax.StAXResult; +import javax.xml.transform.stream.StreamResult; + +import org.custommonkey.xmlunit.XMLTestCase; +import static org.easymock.EasyMock.*; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.oxm.XmlMappingException; +import org.springframework.oxm.jaxb2.FlightType; +import org.springframework.oxm.jaxb2.Flights; +import org.springframework.oxm.jaxb2.ObjectFactory; +import org.springframework.oxm.mime.MimeContainer; +import org.springframework.util.FileCopyUtils; +import org.springframework.xml.transform.StaxResult; +import org.springframework.xml.transform.StringResult; + +public class Jaxb2MarshallerTest extends XMLTestCase { + + private static final String CONTEXT_PATH = "org.springframework.oxm.jaxb2"; + + private static final String EXPECTED_STRING = + "" + + "42"; + + private Jaxb2Marshaller marshaller; + + private Flights flights; + + protected void setUp() throws Exception { + marshaller = new Jaxb2Marshaller(); + marshaller.setContextPath(CONTEXT_PATH); + marshaller.afterPropertiesSet(); + FlightType flight = new FlightType(); + flight.setNumber(42L); + flights = new Flights(); + flights.getFlight().add(flight); + } + + public void testMarshalDOMResult() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder(); + Document document = builder.newDocument(); + DOMResult domResult = new DOMResult(document); + marshaller.marshal(flights, domResult); + Document expected = builder.newDocument(); + Element flightsElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:flights"); + expected.appendChild(flightsElement); + Element flightElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:flight"); + flightsElement.appendChild(flightElement); + Element numberElement = expected.createElementNS("http://samples.springframework.org/flight", "tns:number"); + flightElement.appendChild(numberElement); + Text text = expected.createTextNode("42"); + numberElement.appendChild(text); + assertXMLEqual("Marshaller writes invalid DOMResult", expected, document); + } + + public void testMarshalStreamResultWriter() throws Exception { + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStreamResultOutputStream() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + StreamResult result = new StreamResult(os); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, + new String(os.toByteArray(), "UTF-8")); + } + + public void testMarshalStaxResultXMLStreamWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer); + StaxResult result = new StaxResult(streamWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStaxResultXMLEventWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer); + StaxResult result = new StaxResult(eventWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStaxResultXMLStreamWriterJaxp14() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer); + StAXResult result = new StAXResult(streamWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStaxResultXMLEventWriterJaxp14() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer); + StAXResult result = new StAXResult(eventWriter); + marshaller.marshal(flights, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testProperties() throws Exception { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); + marshaller.setContextPath(CONTEXT_PATH); + marshaller.setMarshallerProperties( + Collections.singletonMap(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE)); + marshaller.afterPropertiesSet(); + } + + public void testNoContextPathOrClassesToBeBound() throws Exception { + try { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); + marshaller.afterPropertiesSet(); + fail("Should have thrown an IllegalArgumentException"); + } + catch (IllegalArgumentException e) { + } + } + + public void testInvalidContextPath() throws Exception { + try { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); + marshaller.setContextPath("ab"); + marshaller.afterPropertiesSet(); + fail("Should have thrown an XmlMappingException"); + } + catch (XmlMappingException ex) { + } + } + + public void testMarshalInvalidClass() throws Exception { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); + marshaller.setClassesToBeBound(new Class[]{FlightType.class}); + marshaller.afterPropertiesSet(); + Result result = new StreamResult(new StringWriter()); + Flights flights = new Flights(); + try { + marshaller.marshal(flights, result); + fail("Should have thrown an MarshallingFailureException"); + } + catch (XmlMappingException ex) { + // expected + } + } + + public void testMarshalSaxResult() throws Exception { + ContentHandler handlerMock = createStrictMock(ContentHandler.class); + handlerMock.setDocumentLocator(isA(Locator.class)); + handlerMock.startDocument(); + handlerMock.startPrefixMapping("", "http://samples.springframework.org/flight"); + handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("flights"), eq("flights"), + isA(Attributes.class)); + handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("flight"), eq("flight"), + isA(Attributes.class)); + handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("number"), eq("number"), + isA(Attributes.class)); + handlerMock.characters(isA(char[].class), eq(0), eq(2)); + handlerMock.endElement("http://samples.springframework.org/flight", "number", "number"); + handlerMock.endElement("http://samples.springframework.org/flight", "flight", "flight"); + handlerMock.endElement("http://samples.springframework.org/flight", "flights", "flights"); + handlerMock.endPrefixMapping(""); + handlerMock.endDocument(); + replay(handlerMock); + + SAXResult result = new SAXResult(handlerMock); + marshaller.marshal(flights, result); + verify(handlerMock); + } + + public void testSupportsContextPath() throws Exception { + Method createFlights = ObjectFactory.class.getDeclaredMethod("createFlights"); + assertTrue("Jaxb2Marshaller does not support Flights", + marshaller.supports(createFlights.getGenericReturnType())); + Method createFlight = ObjectFactory.class.getDeclaredMethod("createFlight", FlightType.class); + assertTrue("Jaxb2Marshaller does not support JAXBElement", + marshaller.supports(createFlight.getGenericReturnType())); + assertFalse("Jaxb2Marshaller supports non-parameterized JAXBElement", marshaller.supports(JAXBElement.class)); + JAXBElement testElement = + new JAXBElement(new QName("something"), Jaxb2MarshallerTest.class, null, this); + assertFalse("Jaxb2Marshaller supports wrong JAXBElement", marshaller.supports(testElement.getClass())); + } + + public void testSupportsClassesToBeBound() throws Exception { + marshaller = new Jaxb2Marshaller(); + marshaller.setClassesToBeBound(new Class[]{Flights.class, FlightType.class}); + marshaller.afterPropertiesSet(); + Method createFlights = ObjectFactory.class.getDeclaredMethod("createFlights"); + assertTrue("Jaxb2Marshaller does not support Flights", + marshaller.supports(createFlights.getGenericReturnType())); + Method createFlight = ObjectFactory.class.getDeclaredMethod("createFlight", FlightType.class); + assertTrue("Jaxb2Marshaller does not support JAXBElement", + marshaller.supports(createFlight.getGenericReturnType())); + assertFalse("Jaxb2Marshaller supports non-parameterized JAXBElement", marshaller.supports(JAXBElement.class)); + JAXBElement testElement = + new JAXBElement(new QName("something"), Jaxb2MarshallerTest.class, null, this); + assertFalse("Jaxb2Marshaller supports wrong JAXBElement", marshaller.supports(testElement.getClass())); + } + + public void testSupportsPrimitives() throws Exception { + Method primitives = getClass().getDeclaredMethod("primitives", JAXBElement.class, JAXBElement.class, + JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, + JAXBElement.class); + Type[] types = primitives.getGenericParameterTypes(); + for (int i = 0; i < types.length; i++) { + ParameterizedType type = (ParameterizedType) types[i]; + assertTrue("Jaxb2Marshaller does not support " + type, marshaller.supports(types[i])); + } + } + + public void testSupportsStandards() throws Exception { + Method standards = getClass().getDeclaredMethod("standards", JAXBElement.class, JAXBElement.class, + JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, + JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, JAXBElement.class, + JAXBElement.class, JAXBElement.class); + Type[] types = standards.getGenericParameterTypes(); + for (int i = 0; i < types.length; i++) { + ParameterizedType type = (ParameterizedType) types[i]; + assertTrue("Jaxb2Marshaller does not support " + type, marshaller.supports(types[i])); + } + } + + public void testMarshalAttachments() throws Exception { + marshaller = new Jaxb2Marshaller(); + marshaller.setClassesToBeBound(new Class[]{BinaryObject.class}); + marshaller.setMtomEnabled(true); + marshaller.afterPropertiesSet(); + MimeContainer mimeContainer = createMock(MimeContainer.class); + + Resource logo = new ClassPathResource("spring-ws.png", getClass()); + DataHandler dataHandler = new DataHandler(new FileDataSource(logo.getFile())); + + expect(mimeContainer.convertToXopPackage()).andReturn(true); + mimeContainer.addAttachment(isA(String.class), isA(DataHandler.class)); + expectLastCall().times(3); + + replay(mimeContainer); + byte[] bytes = FileCopyUtils.copyToByteArray(logo.getInputStream()); + BinaryObject object = new BinaryObject(bytes, dataHandler); + Result result = new StringResult(); + marshaller.marshal(object, result, mimeContainer); + verify(mimeContainer); + assertTrue("No XML written", result.toString().length() > 0); + } + + private void primitives(JAXBElement bool, + JAXBElement aByte, + JAXBElement aShort, + JAXBElement anInteger, + JAXBElement aLong, + JAXBElement aFloat, + JAXBElement aDouble, + JAXBElement byteArray) { + } + + private void standards(JAXBElement string, + JAXBElement integer, + JAXBElement decimal, + JAXBElement calendar, + JAXBElement date, + JAXBElement qName, + JAXBElement uri, + JAXBElement xmlGregorianCalendar, + JAXBElement duration, + JAXBElement object, + JAXBElement image, + JAXBElement dataHandler, + JAXBElement source, + JAXBElement uuid) { + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java new file mode 100644 index 00000000000..a0689559c1a --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java @@ -0,0 +1,196 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jaxb; + +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.xml.bind.JAXBElement; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLEventReader; +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 junit.framework.TestCase; +import static org.easymock.EasyMock.*; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.oxm.jaxb2.FlightType; +import org.springframework.oxm.jaxb2.Flights; +import org.springframework.oxm.mime.MimeContainer; +import org.springframework.xml.transform.StaxSource; +import org.springframework.xml.transform.StringSource; + +public class Jaxb2UnmarshallerTest extends TestCase { + + private static final String INPUT_STRING = "" + + "42"; + + private Jaxb2Marshaller unmarshaller; + + protected void setUp() throws Exception { + unmarshaller = new Jaxb2Marshaller(); + unmarshaller.setContextPath("org.springframework.oxm.jaxb2"); + unmarshaller.setSchema(new ClassPathResource("org/springframework/oxm/flight.xsd")); + unmarshaller.afterPropertiesSet(); + } + + public void testUnmarshalDomSource() throws Exception { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document document = builder.newDocument(); + Element flightsElement = document.createElementNS("http://samples.springframework.org/flight", "tns:flights"); + document.appendChild(flightsElement); + Element flightElement = document.createElementNS("http://samples.springframework.org/flight", "tns:flight"); + flightsElement.appendChild(flightElement); + Element numberElement = document.createElementNS("http://samples.springframework.org/flight", "tns:number"); + flightElement.appendChild(numberElement); + Text text = document.createTextNode("42"); + numberElement.appendChild(text); + DOMSource source = new DOMSource(document); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStreamSourceReader() throws Exception { + StreamSource source = new StreamSource(new StringReader(INPUT_STRING)); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStreamSourceInputStream() throws Exception { + StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes("UTF-8"))); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalSAXSource() throws Exception { + XMLReader reader = XMLReaderFactory.createXMLReader(); + SAXSource source = new SAXSource(reader, new InputSource(new StringReader(INPUT_STRING))); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStaxSourceXmlStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + StaxSource source = new StaxSource(streamReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStaxSourceXmlEventReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(INPUT_STRING)); + StaxSource source = new StaxSource(eventReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStaxSourceXmlStreamReaderJaxp14() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + StAXSource source = new StAXSource(streamReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testUnmarshalStaxSourceXmlEventReaderJaxp14() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(INPUT_STRING)); + StAXSource source = new StAXSource(eventReader); + Object flights = unmarshaller.unmarshal(source); + testFlights(flights); + } + + public void testMarshalAttachments() throws Exception { + unmarshaller = new Jaxb2Marshaller(); + unmarshaller.setClassesToBeBound(new Class[]{BinaryObject.class}); + unmarshaller.setMtomEnabled(true); + unmarshaller.afterPropertiesSet(); + MimeContainer mimeContainer = createMock(MimeContainer.class); + + Resource logo = new ClassPathResource("spring-ws.png", getClass()); + DataHandler dataHandler = new DataHandler(new FileDataSource(logo.getFile())); + + expect(mimeContainer.isXopPackage()).andReturn(true); + expect(mimeContainer.getAttachment( + "<6b76528d-7a9c-4def-8e13-095ab89e9bb7@http://springframework.org/spring-ws>")) + .andReturn(dataHandler); + expect(mimeContainer.getAttachment( + "<99bd1592-0521-41a2-9688-a8bfb40192fb@http://springframework.org/spring-ws>")) + .andReturn(dataHandler); + expect(mimeContainer.getAttachment("696cfb9a-4d2d-402f-bb5c-59fa69e7f0b3@spring-ws.png")) + .andReturn(dataHandler); + replay(mimeContainer); + String content = "" + "" + + "" + + "" + "" + + "" + + "" + + "696cfb9a-4d2d-402f-bb5c-59fa69e7f0b3@spring-ws.png" + + ""; + + Source source = new StringSource(content); + Object result = unmarshaller.unmarshal(source, mimeContainer); + assertTrue("Result is not a BinaryObject", result instanceof BinaryObject); + verify(mimeContainer); + BinaryObject object = (BinaryObject) result; + assertNotNull("bytes property not set", object.getBytes()); + assertTrue("bytes property not set", object.getBytes().length > 0); + assertNotNull("datahandler property not set", object.getSwaDataHandler()); + } + + private void testFlights(Object o) { + Flights flights = (Flights) o; + assertNotNull("Flights is null", flights); + assertEquals("Invalid amount of flight elements", 1, flights.getFlight().size()); + testFlight(flights.getFlight().get(0)); + } + + private void testFlight(Object o) { + FlightType flight = (FlightType) o; + assertNotNull("Flight is null", flight); + assertEquals("Number is invalid", 42L, flight.getNumber()); + } + + public void testUnmarshalPartialStaxSourceXmlStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + streamReader.nextTag(); // skip to flights + streamReader.nextTag(); // skip to flight + StaxSource source = new StaxSource(streamReader); + JAXBElement element = (JAXBElement) unmarshaller.unmarshal(source); + FlightType flight = element.getValue(); + testFlight(flight); + } + + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/JaxbUtilsTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/JaxbUtilsTest.java new file mode 100644 index 00000000000..393770fb468 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/JaxbUtilsTest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jaxb; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.MarshalException; +import javax.xml.bind.UnmarshalException; +import javax.xml.bind.ValidationException; + +import junit.framework.TestCase; + +public class JaxbUtilsTest extends TestCase { + + public void testGetJaxbVersion() throws Exception { + assertEquals("Invalid JAXB version", JaxbUtils.JAXB_2, JaxbUtils.getJaxbVersion()); + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/FlightType.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/FlightType.java new file mode 100644 index 00000000000..c34003aa922 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/FlightType.java @@ -0,0 +1,30 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +public class FlightType { + + protected long number; + + public long getNumber() { + return this.number; + } + + public void setNumber(long number) { + this.number = number; + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/Flights.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/Flights.java new file mode 100644 index 00000000000..739a3ab9bf2 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/Flights.java @@ -0,0 +1,36 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import java.util.ArrayList; + +public class Flights { + + protected ArrayList flightList = new ArrayList(); + + public void addFlight(FlightType flight) { + flightList.add(flight); + } + + public FlightType getFlight(int index) { + return (FlightType) flightList.get(index); + } + + public int sizeFlightList() { + return flightList.size(); + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxMarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxMarshallerTest.java new file mode 100644 index 00000000000..38c3fa275fe --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxMarshallerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import org.custommonkey.xmlunit.XMLUnit; + +import org.springframework.oxm.AbstractMarshallerTestCase; +import org.springframework.oxm.Marshaller; +import org.springframework.xml.transform.StringResult; + +public class JibxMarshallerTest extends AbstractMarshallerTestCase { + + protected Marshaller createMarshaller() throws Exception { + JibxMarshaller marshaller = new JibxMarshaller(); + marshaller.setTargetClass(Flights.class); + marshaller.afterPropertiesSet(); + return marshaller; + } + + protected Object createFlights() { + Flights flights = new Flights(); + FlightType flight = new FlightType(); + flight.setNumber(42L); + flights.addFlight(flight); + return flights; + } + + public void testAfterPropertiesSetNoContextPath() throws Exception { + try { + JibxMarshaller marshaller = new JibxMarshaller(); + marshaller.afterPropertiesSet(); + fail("Should have thrown an IllegalArgumentException"); + } + catch (IllegalArgumentException e) { + } + } + + public void testIndentation() throws Exception { + ((JibxMarshaller) marshaller).setIndent(4); + StringResult result = new StringResult(); + marshaller.marshal(flights, result); + XMLUnit.setIgnoreWhitespace(false); + String expected = "\n" + + "\n" + " \n" + + " 42\n" + " \n" + ""; + assertXMLEqual(expected, result.toString()); + } + + public void testEncodingAndStandalone() throws Exception { + ((JibxMarshaller) marshaller).setEncoding("ISO-8859-1"); + ((JibxMarshaller) marshaller).setStandalone(Boolean.TRUE); + StringResult result = new StringResult(); + marshaller.marshal(flights, result); + assertTrue("Encoding and standalone not set", + result.toString().startsWith("")); + } + + public void testSupports() throws Exception { + assertTrue("JibxMarshaller does not support Flights", marshaller.supports(Flights.class)); + assertTrue("JibxMarshaller does not support FlightType", marshaller.supports(FlightType.class)); + assertFalse("JibxMarshaller supports illegal type", marshaller.supports(getClass())); + } + + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUnmarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUnmarshallerTest.java new file mode 100644 index 00000000000..35db639d308 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUnmarshallerTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.jibx; + +import org.springframework.oxm.AbstractUnmarshallerTestCase; +import org.springframework.oxm.Unmarshaller; + +public class JibxUnmarshallerTest extends AbstractUnmarshallerTestCase { + + protected Unmarshaller createUnmarshaller() throws Exception { + JibxMarshaller unmarshaller = new JibxMarshaller(); + unmarshaller.setTargetClass(Flights.class); + unmarshaller.afterPropertiesSet(); + return unmarshaller; + } + + protected void testFlights(Object o) { + Flights flights = (Flights) o; + assertNotNull("Flights is null", flights); + assertEquals("Invalid amount of flight elements", 1, flights.sizeFlightList()); + testFlight(flights.getFlight(0)); + } + + protected void testFlight(Object o) { + FlightType flight = (FlightType) o; + assertNotNull("Flight is null", flight); + assertEquals("Number is invalid", 42L, flight.getNumber()); + } + + public void testUnmarshalPartialStaxSourceXmlStreamReader() throws Exception { + // JiBX does not support reading XML fragments, hence the override here + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUtilsTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUtilsTest.java new file mode 100644 index 00000000000..545139a27d3 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/jibx/JibxUtilsTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.jibx; + +import junit.framework.TestCase; +import org.jibx.runtime.JiBXException; +import org.jibx.runtime.ValidationException; + +public class JibxUtilsTest extends TestCase { + + public void testConvertMarshallingException() throws Exception { + assertTrue("Invalid exception conversion", + JibxUtils.convertJibxException(new JiBXException(""), true) instanceof JibxMarshallingFailureException); + } + + public void testConvertUnmarshallingException() throws Exception { + assertTrue("Invalid exception conversion", JibxUtils + .convertJibxException(new JiBXException(""), false) instanceof JibxUnmarshallingFailureException); + } + + public void testConvertValidationException() throws Exception { + assertTrue("Invalid exception conversion", JibxUtils + .convertJibxException(new ValidationException(""), true) instanceof JibxValidationFailureException); + } +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingMessageConverterTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingMessageConverterTest.java new file mode 100644 index 00000000000..3ec3682568d --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingMessageConverterTest.java @@ -0,0 +1,156 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.support; + +import javax.jms.BytesMessage; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.xml.transform.StringResult; +import org.springframework.xml.transform.StringSource; + +public class MarshallingMessageConverterTest extends TestCase { + + private MarshallingMessageConverter converter; + + private MockControl marshallerControl; + + private Marshaller marshallerMock; + + private MockControl unmarshallerControl; + + private Unmarshaller unmarshallerMock; + + private MockControl sessionControl; + + private Session sessionMock; + + protected void setUp() throws Exception { + marshallerControl = MockControl.createControl(Marshaller.class); + marshallerMock = (Marshaller) marshallerControl.getMock(); + unmarshallerControl = MockControl.createControl(Unmarshaller.class); + unmarshallerMock = (Unmarshaller) unmarshallerControl.getMock(); + converter = new MarshallingMessageConverter(marshallerMock, unmarshallerMock); + sessionControl = MockControl.createControl(Session.class); + sessionMock = (Session) sessionControl.getMock(); + + } + + public void testToBytesMessage() throws Exception { + MockControl bytesMessageControl = MockControl.createControl(BytesMessage.class); + BytesMessage bytesMessageMock = (BytesMessage) bytesMessageControl.getMock(); + Object toBeMarshalled = new Object(); + + sessionControl.expectAndReturn(sessionMock.createBytesMessage(), bytesMessageMock); + marshallerMock.marshal(toBeMarshalled, new StringResult()); + marshallerControl.setMatcher(MockControl.ALWAYS_MATCHER); + bytesMessageMock.writeBytes(new byte[0]); + bytesMessageControl.setMatcher(MockControl.ALWAYS_MATCHER); + + marshallerControl.replay(); + unmarshallerControl.replay(); + sessionControl.replay(); + bytesMessageControl.replay(); + + converter.toMessage(toBeMarshalled, sessionMock); + + marshallerControl.verify(); + unmarshallerControl.verify(); + sessionControl.verify(); + bytesMessageControl.verify(); + } + + public void testFromBytesMessage() throws Exception { + MockControl bytesMessageControl = MockControl.createControl(BytesMessage.class); + BytesMessage bytesMessageMock = (BytesMessage) bytesMessageControl.getMock(); + Object unmarshalled = new Object(); + + bytesMessageControl.expectAndReturn(bytesMessageMock.getBodyLength(), 10); + bytesMessageMock.readBytes(new byte[0]); + bytesMessageControl.setMatcher(MockControl.ALWAYS_MATCHER); + bytesMessageControl.setReturnValue(0); + unmarshallerMock.unmarshal(new StringSource("")); + unmarshallerControl.setMatcher(MockControl.ALWAYS_MATCHER); + unmarshallerControl.setReturnValue(unmarshalled); + + marshallerControl.replay(); + unmarshallerControl.replay(); + sessionControl.replay(); + bytesMessageControl.replay(); + + Object result = converter.fromMessage(bytesMessageMock); + assertEquals("Invalid result", result, unmarshalled); + + marshallerControl.verify(); + unmarshallerControl.verify(); + sessionControl.verify(); + bytesMessageControl.verify(); + } + + public void testToTextMessage() throws Exception { + converter.setMarshalTo(MarshallingMessageConverter.MARSHAL_TO_TEXT_MESSAGE); + MockControl textMessageControl = MockControl.createControl(TextMessage.class); + TextMessage textMessageMock = (TextMessage) textMessageControl.getMock(); + Object toBeMarshalled = new Object(); + + sessionControl.expectAndReturn(sessionMock.createTextMessage(""), textMessageMock); + marshallerMock.marshal(toBeMarshalled, new StringResult()); + marshallerControl.setMatcher(MockControl.ALWAYS_MATCHER); + + marshallerControl.replay(); + unmarshallerControl.replay(); + sessionControl.replay(); + textMessageControl.replay(); + + converter.toMessage(toBeMarshalled, sessionMock); + + marshallerControl.verify(); + unmarshallerControl.verify(); + sessionControl.verify(); + textMessageControl.verify(); + } + + public void testFromTextMessage() throws Exception { + MockControl textMessageControl = MockControl.createControl(TextMessage.class); + TextMessage textMessageMock = (TextMessage) textMessageControl.getMock(); + Object unmarshalled = new Object(); + + unmarshallerMock.unmarshal(new StringSource("")); + unmarshallerControl.setMatcher(MockControl.ALWAYS_MATCHER); + unmarshallerControl.setReturnValue(unmarshalled); + textMessageControl.expectAndReturn(textMessageMock.getText(), ""); + + marshallerControl.replay(); + unmarshallerControl.replay(); + sessionControl.replay(); + textMessageControl.replay(); + + Object result = converter.fromMessage(textMessageMock); + assertEquals("Invalid result", result, unmarshalled); + + marshallerControl.verify(); + unmarshallerControl.verify(); + sessionControl.verify(); + textMessageControl.verify(); + } + +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingViewTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingViewTest.java new file mode 100644 index 00000000000..54d982e3797 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/support/MarshallingViewTest.java @@ -0,0 +1,135 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.support; + +import java.util.HashMap; +import java.util.Map; +import javax.servlet.ServletException; +import javax.xml.transform.stream.StreamResult; + +import junit.framework.Assert; +import junit.framework.TestCase; +import org.easymock.MockControl; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.oxm.Marshaller; + +public class MarshallingViewTest extends TestCase { + + private MarshallingView view; + + private MockControl control; + + private Marshaller marshallerMock; + + protected void setUp() throws Exception { + control = MockControl.createControl(Marshaller.class); + marshallerMock = (Marshaller) control.getMock(); + view = new MarshallingView(marshallerMock); + } + + public void testGetContentType() { + Assert.assertEquals("Invalid content type", "application/xml", view.getContentType()); + } + + public void testRenderModelKey() throws Exception { + Object toBeMarshalled = new Object(); + String modelKey = "key"; + view.setModelKey(modelKey); + Map model = new HashMap(); + model.put(modelKey, toBeMarshalled); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + control.expectAndReturn(marshallerMock.supports(Object.class), true); + marshallerMock.marshal(toBeMarshalled, new StreamResult(response.getOutputStream())); + control.setMatcher(MockControl.ALWAYS_MATCHER); + + control.replay(); + view.render(model, request, response); + Assert.assertEquals("Invalid content type", "application/xml", response.getContentType()); + Assert.assertEquals("Invalid content length", 0, response.getContentLength()); + control.verify(); + } + + public void testRenderModelKeyUnsupported() throws Exception { + Object toBeMarshalled = new Object(); + String modelKey = "key"; + view.setModelKey(modelKey); + Map model = new HashMap(); + model.put(modelKey, toBeMarshalled); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + control.expectAndReturn(marshallerMock.supports(Object.class), false); + + control.replay(); + try { + view.render(model, request, response); + fail("ServletException expected"); + } + catch (ServletException ex) { + // expected + } + control.verify(); + } + + public void testRenderNoModelKey() throws Exception { + Object toBeMarshalled = new Object(); + String modelKey = "key"; + Map model = new HashMap(); + model.put(modelKey, toBeMarshalled); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + control.expectAndReturn(marshallerMock.supports(Object.class), true); + marshallerMock.marshal(toBeMarshalled, new StreamResult(response.getOutputStream())); + control.setMatcher(MockControl.ALWAYS_MATCHER); + + control.replay(); + view.render(model, request, response); + Assert.assertEquals("Invalid content type", "application/xml", response.getContentType()); + Assert.assertEquals("Invalid content length", 0, response.getContentLength()); + control.verify(); + } + + public void testRenderUnsupportedModel() throws Exception { + Object toBeMarshalled = new Object(); + String modelKey = "key"; + Map model = new HashMap(); + model.put(modelKey, toBeMarshalled); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + control.expectAndReturn(marshallerMock.supports(Object.class), false); + + control.replay(); + try { + view.render(model, request, response); + fail("ServletException expected"); + } + catch (ServletException ex) { + // expected + } + control.verify(); + } +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallerTest.java new file mode 100644 index 00000000000..5a390a77a3b --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansMarshallerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import java.io.ByteArrayOutputStream; +import javax.xml.transform.stream.StreamResult; + +import org.apache.xmlbeans.XmlObject; +import org.springframework.oxm.AbstractMarshallerTestCase; +import org.springframework.oxm.Marshaller; +import org.springframework.samples.flight.FlightType; +import org.springframework.samples.flight.FlightsDocument; +import org.springframework.samples.flight.FlightsDocument.Flights; + +public class XmlBeansMarshallerTest extends AbstractMarshallerTestCase { + + protected Marshaller createMarshaller() throws Exception { + return new XmlBeansMarshaller(); + } + + public void testMarshalNonXmlObject() throws Exception { + try { + marshaller.marshal(new Object(), new StreamResult(new ByteArrayOutputStream())); + fail("XmlBeansMarshaller did not throw ClassCastException for non-XmlObject"); + } + catch (ClassCastException e) { + // Expected behavior + } + } + + protected Object createFlights() { + FlightsDocument flightsDocument = FlightsDocument.Factory.newInstance(); + Flights flights = flightsDocument.addNewFlights(); + FlightType flightType = flights.addNewFlight(); + flightType.setNumber(42L); + return flightsDocument; + } + + public void testSupports() throws Exception { + assertTrue("XmlBeansMarshaller does not support XmlObject", marshaller.supports(XmlObject.class)); + assertFalse("XmlBeansMarshaller supports other objects", marshaller.supports(Object.class)); + assertTrue("XmlBeansMarshaller does not support FlightsDocument", marshaller.supports(FlightsDocument.class)); + assertTrue("XmlBeansMarshaller does not support Flights", marshaller.supports(Flights.class)); + assertTrue("XmlBeansMarshaller does not support FlightType", marshaller.supports(FlightType.class)); + } +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallerTest.java new file mode 100644 index 00000000000..ab6c835960a --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUnmarshallerTest.java @@ -0,0 +1,89 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import java.io.StringReader; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; + +import org.springframework.oxm.AbstractUnmarshallerTestCase; +import org.springframework.oxm.Unmarshaller; +import org.springframework.samples.flight.FlightDocument; +import org.springframework.samples.flight.FlightType; +import org.springframework.samples.flight.FlightsDocument; +import org.springframework.samples.flight.FlightsDocument.Flights; +import org.springframework.xml.transform.StaxSource; +import org.springframework.xml.transform.StringSource; + +public class XmlBeansUnmarshallerTest extends AbstractUnmarshallerTestCase { + + protected Unmarshaller createUnmarshaller() throws Exception { + return new XmlBeansMarshaller(); + } + + protected void testFlights(Object o) { + FlightsDocument flightsDocument = (FlightsDocument) o; + assertNotNull("FlightsDocument is null", flightsDocument); + Flights flights = flightsDocument.getFlights(); + assertEquals("Invalid amount of flight elements", 1, flights.sizeOfFlightArray()); + testFlight(flights.getFlightArray(0)); + } + + protected void testFlight(Object o) { + FlightType flight = null; + if (o instanceof FlightType) { + flight = (FlightType) o; + } + else if (o instanceof FlightDocument) { + FlightDocument flightDocument = (FlightDocument) o; + flight = flightDocument.getFlight(); + } + assertNotNull("Flight is null", flight); + assertEquals("Number is invalid", 42L, flight.getNumber()); + } + + public void testUnmarshalPartialStaxSourceXmlStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + streamReader.nextTag(); // skip to flights + assertEquals("Invalid element", new QName("http://samples.springframework.org/flight", "flights"), + streamReader.getName()); + streamReader.nextTag(); // skip to flight + assertEquals("Invalid element", new QName("http://samples.springframework.org/flight", "flight"), + streamReader.getName()); + StaxSource source = new StaxSource(streamReader); + Object flight = unmarshaller.unmarshal(source); + testFlight(flight); + } + + public void testValidate() throws Exception { + ((XmlBeansMarshaller) unmarshaller).setValidating(true); + + try { + String invalidInput = "" + + "abc"; + unmarshaller.unmarshal(new StringSource(invalidInput)); + fail("Expected a XmlBeansValidationFailureException"); + } + catch (XmlBeansValidationFailureException ex) { + // expected + } + + + } + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUtilsTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUtilsTest.java new file mode 100644 index 00000000000..9b765b1fef1 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlBeansUtilsTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.oxm.xmlbeans; + +import junit.framework.TestCase; +import org.apache.xmlbeans.XMLStreamValidationException; +import org.apache.xmlbeans.XmlError; +import org.apache.xmlbeans.XmlException; +import org.xml.sax.SAXException; + +public class XmlBeansUtilsTest extends TestCase { + + public void testConvertXMLStreamValidationException() { + assertTrue("Invalid exception conversion", XmlBeansUtils.convertXmlBeansException( + new XMLStreamValidationException(XmlError.forMessage("")), + true) instanceof XmlBeansValidationFailureException); + + } + + public void testConvertXmlException() { + assertTrue("Invalid exception conversion", XmlBeansUtils + .convertXmlBeansException(new XmlException(""), true) instanceof XmlBeansMarshallingFailureException); + assertTrue("Invalid exception conversion", XmlBeansUtils.convertXmlBeansException(new XmlException(""), + false) instanceof XmlBeansUnmarshallingFailureException); + } + + public void testConvertSAXException() { + assertTrue("Invalid exception conversion", XmlBeansUtils + .convertXmlBeansException(new SAXException(""), true) instanceof XmlBeansMarshallingFailureException); + assertTrue("Invalid exception conversion", XmlBeansUtils.convertXmlBeansException(new SAXException(""), + false) instanceof XmlBeansUnmarshallingFailureException); + } + + public void testFallbackException() { + assertTrue("Invalid exception conversion", + XmlBeansUtils.convertXmlBeansException(new Exception(""), false) instanceof XmlBeansSystemException); + + } + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBeanTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBeanTest.java new file mode 100644 index 00000000000..26fc31de947 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xmlbeans/XmlOptionsFactoryBeanTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xmlbeans; + +import java.util.Collections; + +import junit.framework.TestCase; +import org.apache.xmlbeans.XmlOptions; + +public class XmlOptionsFactoryBeanTest extends TestCase { + + private XmlOptionsFactoryBean factoryBean; + + protected void setUp() throws Exception { + factoryBean = new XmlOptionsFactoryBean(); + } + + public void testXmlOptionsFactoryBean() throws Exception { + factoryBean.setOptions(Collections.singletonMap(XmlOptions.SAVE_PRETTY_PRINT, Boolean.TRUE)); + factoryBean.afterPropertiesSet(); + XmlOptions xmlOptions = (XmlOptions) factoryBean.getObject(); + assertNotNull("No XmlOptions returned", xmlOptions); + assertTrue("Option not set", xmlOptions.hasOption(XmlOptions.SAVE_PRETTY_PRINT)); + assertFalse("Invalid option set", xmlOptions.hasOption(XmlOptions.LOAD_LINE_NUMBERS)); + } +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/AnnotationXStreamMarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/AnnotationXStreamMarshallerTest.java new file mode 100644 index 00000000000..ab9d56b60ce --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/AnnotationXStreamMarshallerTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import java.io.StringWriter; +import javax.xml.transform.stream.StreamResult; + +import org.custommonkey.xmlunit.XMLTestCase; + +public class AnnotationXStreamMarshallerTest extends XMLTestCase { + + private AnnotationXStreamMarshaller marshaller; + + private static final String EXPECTED_STRING = "42"; + + private Flight flight; + + protected void setUp() throws Exception { + marshaller = new AnnotationXStreamMarshaller(); + marshaller.setAnnotatedClass(Flight.class); + flight = new Flight(); + flight.setFlightNumber(42L); + } + + public void testMarshalStreamResultWriter() throws Exception { + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + marshaller.marshal(flight, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/Flight.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/Flight.java new file mode 100644 index 00000000000..8152f1e2d2d --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/Flight.java @@ -0,0 +1,34 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("flight") +public class Flight { + + @XStreamAlias("number") + private long flightNumber; + + public long getFlightNumber() { + return flightNumber; + } + + public void setFlightNumber(long number) { + this.flightNumber = number; + } +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTest.java new file mode 100644 index 00000000000..e7e941465ad --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTest.java @@ -0,0 +1,222 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.Properties; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamResult; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.extended.EncodedByteArrayConverter; +import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver; +import org.custommonkey.xmlunit.XMLTestCase; +import org.easymock.MockControl; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.xml.sax.ContentHandler; + +import org.springframework.xml.transform.StaxResult; +import org.springframework.xml.transform.StringResult; +import org.springframework.xml.transform.StringSource; + +public class XStreamMarshallerTest extends XMLTestCase { + + private static final String EXPECTED_STRING = "42"; + + private XStreamMarshaller marshaller; + + private Flight flight; + + protected void setUp() throws Exception { + marshaller = new XStreamMarshaller(); + Properties aliases = new Properties(); + aliases.setProperty("flight", Flight.class.getName()); + marshaller.setAliases(aliases); + flight = new Flight(); + flight.setFlightNumber(42L); + } + + public void testMarshalDOMResult() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder(); + Document document = builder.newDocument(); + DOMResult domResult = new DOMResult(document); + marshaller.marshal(flight, domResult); + Document expected = builder.newDocument(); + Element flightElement = expected.createElement("flight"); + expected.appendChild(flightElement); + Element numberElement = expected.createElement("flightNumber"); + flightElement.appendChild(numberElement); + Text text = expected.createTextNode("42"); + numberElement.appendChild(text); + assertXMLEqual("Marshaller writes invalid DOMResult", expected, document); + } + + // see SWS-392 + public void testMarshalDOMResultToExistentDocument() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder(); + Document existent = builder.newDocument(); + Element rootElement = existent.createElement("root"); + Element flightsElement = existent.createElement("flights"); + rootElement.appendChild(flightsElement); + existent.appendChild(rootElement); + + // marshall into the existent document + DOMResult domResult = new DOMResult(flightsElement); + marshaller.marshal(flight, domResult); + + Document expected = builder.newDocument(); + Element eRootElement = expected.createElement("root"); + Element eFlightsElement = expected.createElement("flights"); + Element eFlightElement = expected.createElement("flight"); + eRootElement.appendChild(eFlightsElement); + eFlightsElement.appendChild(eFlightElement); + expected.appendChild(eRootElement); + Element eNumberElement = expected.createElement("flightNumber"); + eFlightElement.appendChild(eNumberElement); + Text text = expected.createTextNode("42"); + eNumberElement.appendChild(text); + assertXMLEqual("Marshaller writes invalid DOMResult", expected, existent); + } + + public void testMarshalStreamResultWriter() throws Exception { + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + marshaller.marshal(flight, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStreamResultOutputStream() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + StreamResult result = new StreamResult(os); + marshaller.marshal(flight, result); + String s = new String(os.toByteArray(), "UTF-8"); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, s); + } + + public void testMarshalSaxResult() throws Exception { + MockControl handlerControl = MockControl.createStrictControl(ContentHandler.class); + handlerControl.setDefaultMatcher(MockControl.ALWAYS_MATCHER); + ContentHandler handlerMock = (ContentHandler) handlerControl.getMock(); + handlerMock.startDocument(); + handlerMock.startElement("", "flight", "flight", null); + handlerMock.startElement("", "number", "number", null); + handlerMock.characters(new char[]{'4', '2'}, 0, 2); + handlerMock.endElement("", "number", "number"); + handlerMock.endElement("", "flight", "flight"); + handlerMock.endDocument(); + + handlerControl.replay(); + SAXResult result = new SAXResult(handlerMock); + marshaller.marshal(flight, result); + handlerControl.verify(); + } + + public void testMarshalStaxResultXMLStreamWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer); + StaxResult result = new StaxResult(streamWriter); + marshaller.marshal(flight, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testMarshalStaxResultXMLEventWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + StringWriter writer = new StringWriter(); + XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer); + StaxResult result = new StaxResult(eventWriter); + marshaller.marshal(flight, result); + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString()); + } + + public void testConverters() throws Exception { + marshaller.setConverters(new Converter[]{new EncodedByteArrayConverter()}); + byte[] buf = new byte[]{0x1, 0x2}; + StringResult result = new StringResult(); + marshaller.marshal(buf, result); + assertXMLEqual("AQI=", result.toString()); + StringSource source = new StringSource(result.toString()); + byte[] bufResult = (byte[]) marshaller.unmarshal(source); + assertTrue("Invalid result", Arrays.equals(buf, bufResult)); + } + + public void testUseAttributesFor() throws Exception { + marshaller.setUseAttributeForTypes(new Class[]{Long.TYPE}); + StringResult result = new StringResult(); + marshaller.marshal(flight, result); + String expected = ""; + assertXMLEqual("Marshaller does not use attributes", expected, result.toString()); + } + + public void testUseAttributesForStringClassMap() throws Exception { + marshaller.setUseAttributeFor(Collections.singletonMap("flightNumber", Long.TYPE)); + StringResult result = new StringResult(); + marshaller.marshal(flight, result); + String expected = ""; + assertXMLEqual("Marshaller does not use attributes", expected, result.toString()); + } + + public void testUseAttributesForClassStringMap() throws Exception { + marshaller.setUseAttributeFor(Collections.singletonMap(Flight.class, "flightNumber")); + StringResult result = new StringResult(); + marshaller.marshal(flight, result); + String expected = ""; + assertXMLEqual("Marshaller does not use attributes", expected, result.toString()); + } + + public void testOmitField() throws Exception { + marshaller.addOmittedField(Flight.class, "flightNumber"); + StringResult result = new StringResult(); + marshaller.marshal(flight, result); + assertXpathNotExists("/flight/flightNumber", result.toString()); + } + + public void testOmitFields() throws Exception { + Map omittedFieldsMap = Collections.singletonMap(Flight.class, "flightNumber"); + marshaller.setOmittedFields(omittedFieldsMap); + StringResult result = new StringResult(); + marshaller.marshal(flight, result); + assertXpathNotExists("/flight/flightNumber", result.toString()); + } + + public void testDriver() throws Exception { + marshaller.setStreamDriver(new JettisonMappedXmlDriver()); + StringResult result = new StringResult(); + marshaller.marshal(flight, result); + assertEquals("Invalid result", "{\"flight\":{\"flightNumber\":\"42\"}}", result.toString()); + Object o = marshaller.unmarshal(new StringSource(result.toString())); + assertTrue("Unmarshalled object is not Flights", o instanceof Flight); + Flight unflight = (Flight) o; + assertNotNull("Flight is null", unflight); + assertEquals("Number is invalid", 42L, unflight.getFlightNumber()); + } + +} diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTest.java new file mode 100644 index 00000000000..3b838f74ab0 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import java.util.Properties; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamSource; + +import junit.framework.TestCase; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +import org.springframework.xml.transform.StaxSource; + +public class XStreamUnmarshallerTest extends TestCase { + + protected static final String INPUT_STRING = "42"; + + private XStreamMarshaller unmarshaller; + + protected void setUp() throws Exception { + unmarshaller = new XStreamMarshaller(); + Properties aliases = new Properties(); + aliases.setProperty("flight", Flight.class.getName()); + unmarshaller.setAliases(aliases); + } + + private void testFlight(Object o) { + assertTrue("Unmarshalled object is not Flights", o instanceof Flight); + Flight flight = (Flight) o; + assertNotNull("Flight is null", flight); + assertEquals("Number is invalid", 42L, flight.getFlightNumber()); + } + + public void testUnmarshalDomSource() throws Exception { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document document = builder.parse(new InputSource(new StringReader(INPUT_STRING))); + DOMSource source = new DOMSource(document); + Object flight = unmarshaller.unmarshal(source); + testFlight(flight); + } + + public void testUnmarshalStaxSourceXmlStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(INPUT_STRING)); + StaxSource source = new StaxSource(streamReader); + Object flights = unmarshaller.unmarshal(source); + testFlight(flights); + } + + public void testUnmarshalStreamSourceInputStream() throws Exception { + StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes("UTF-8"))); + Object flights = unmarshaller.unmarshal(source); + testFlight(flights); + } + + public void testUnmarshalStreamSourceReader() throws Exception { + StreamSource source = new StreamSource(new StringReader(INPUT_STRING)); + Object flights = unmarshaller.unmarshal(source); + testFlight(flights); + } +} + diff --git a/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUtilsTest.java b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUtilsTest.java new file mode 100644 index 00000000000..3e20331f213 --- /dev/null +++ b/org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamUtilsTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.xstream; + +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.mapper.CannotResolveClassException; + +import junit.framework.TestCase; + +public class XStreamUtilsTest extends TestCase { + + public void testConvertStreamException() { + assertTrue("Invalid exception conversion", XStreamUtils.convertXStreamException( + new StreamException(new Exception()), true) instanceof XStreamMarshallingFailureException); + assertTrue("Invalid exception conversion", XStreamUtils.convertXStreamException( + new StreamException(new Exception()), false) instanceof XStreamUnmarshallingFailureException); + } + + public void testConvertCannotResolveClassException() { + assertTrue("Invalid exception conversion", XStreamUtils.convertXStreamException( + new CannotResolveClassException(""), true) instanceof XStreamMarshallingFailureException); + assertTrue("Invalid exception conversion", XStreamUtils.convertXStreamException( + new CannotResolveClassException(""), false) instanceof XStreamUnmarshallingFailureException); + } +} \ No newline at end of file diff --git a/org.springframework.oxm/src/test/resources/log4j.properties b/org.springframework.oxm/src/test/resources/log4j.properties new file mode 100644 index 00000000000..5645c16575a --- /dev/null +++ b/org.springframework.oxm/src/test/resources/log4j.properties @@ -0,0 +1,6 @@ +log4j.rootCategory=INFO, stdout +log4j.logger.org.springframework.oxm=DEBUG + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n \ No newline at end of file diff --git a/org.springframework.oxm/src/test/resources/org/springframework/oxm/castor/mapping.xml b/org.springframework.oxm/src/test/resources/org/springframework/oxm/castor/mapping.xml new file mode 100644 index 00000000000..e85971251c2 --- /dev/null +++ b/org.springframework.oxm/src/test/resources/org/springframework/oxm/castor/mapping.xml @@ -0,0 +1,31 @@ + + + + Castor generated mapping file + + + Default mapping for class + org.springframework.oxm.castor.Flights + + + + + + + + + Default mapping for class + org.springframework.oxm.castor.Flight + + + + + + + \ No newline at end of file diff --git a/org.springframework.oxm/src/test/resources/org/springframework/oxm/config/jaxb2OxmNamespaceHandlerTest.xml b/org.springframework.oxm/src/test/resources/org/springframework/oxm/config/jaxb2OxmNamespaceHandlerTest.xml new file mode 100644 index 00000000000..56f17595429 --- /dev/null +++ b/org.springframework.oxm/src/test/resources/org/springframework/oxm/config/jaxb2OxmNamespaceHandlerTest.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/org.springframework.oxm/src/test/resources/org/springframework/oxm/config/oxmNamespaceHandlerTest.xml b/org.springframework.oxm/src/test/resources/org/springframework/oxm/config/oxmNamespaceHandlerTest.xml new file mode 100644 index 00000000000..861a41ebec7 --- /dev/null +++ b/org.springframework.oxm/src/test/resources/org/springframework/oxm/config/oxmNamespaceHandlerTest.xml @@ -0,0 +1,17 @@ + + + + + + + + + + true + + + + diff --git a/org.springframework.oxm/src/test/resources/org/springframework/oxm/flight.xsd b/org.springframework.oxm/src/test/resources/org/springframework/oxm/flight.xsd new file mode 100644 index 00000000000..5f46e0b91a0 --- /dev/null +++ b/org.springframework.oxm/src/test/resources/org/springframework/oxm/flight.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.oxm/src/test/resources/org/springframework/oxm/jaxb/spring-ws.png b/org.springframework.oxm/src/test/resources/org/springframework/oxm/jaxb/spring-ws.png new file mode 100644 index 0000000000000000000000000000000000000000..f589a8a8023b02a2f4a3d44d15c8f86525790381 GIT binary patch literal 24355 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 + + + + + + + + + + + + diff --git a/org.springframework.oxm/template.mf b/org.springframework.oxm/template.mf new file mode 100644 index 00000000000..cc1ecaeab1b --- /dev/null +++ b/org.springframework.oxm/template.mf @@ -0,0 +1,71 @@ +Bundle-SymbolicName: org.springframework.orm +Bundle-Name: Spring ORM +Bundle-Vendor: SpringSource +Bundle-ManifestVersion: 2 +Import-Package: + com.ibatis.sqlmap.engine.transaction.external;version="[2.3.0.677, 3.0.0)";resolution:=optional, + oracle.toplink.essentials.expressions;version="[2.0.0.b41-beta2, 3.0.0)";resolution:=optional, + org.eclipse.persistence.expressions;version="[1.0.0, 2.0.0)";resolution:=optional +Import-Template: + com.ibatis.*;version="[2.3.0.677, 3.0.0)";resolution:=optional, + javax.jdo.*;version="[2.0.0, 3.0.0)";resolution:=optional, + javax.persistence.*;version="[1.0.0, 2.0.0)";resolution:=optional, + javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional, + javax.transaction.*;version="[1.0.1, 2.0.0)";resolution:=optional, + oracle.toplink.essentials.*;version="[2.0.0.b41-beta2, 3.0.0)";resolution:=optional, + oracle.toplink.exceptions;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.expressions;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.internal.databaseaccess;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.jndi;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.logging;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.publicinterface;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.queryframework;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.sessionbroker;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.sessions;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.threetier;version="[10.1.3, 11.0.0)";resolution:=optional, + oracle.toplink.tools.*;version="[10.1.3, 11.0.0)";resolution:=optional, + org.aopalliance.*;version="[1.0.0, 2.0.0)", + org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", + org.apache.openjpa.persistence.*;version="[1.0.2, 2.0.0)";resolution:=optional, + org.eclipse.persistence.*;version="[1.0.0, 2.0.0)";resolution:=optional, + org.hibernate;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.cache;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.cfg;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.classic;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.connection;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.context;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.criterion;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.dialect;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.ejb;version="[3.3.0.ga, 3.4.0)";resolution:=optional, + org.hibernate.engine;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.event.*;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.exception;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.impl;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.jdbc;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.persister.entity;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.tool.hbm2ddl;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.transaction;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.transform;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.type;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.usertype;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.hibernate.util;version="[3.2.6.ga, 3.3.0)";resolution:=optional, + org.springframework.aop.*;version="[3.0.0, 3.0.1)", + org.springframework.beans.*;version="[3.0.0, 3.0.1)", + org.springframework.context.*;version="[3.0.0, 3.0.1)", + org.springframework.core.*;version="[3.0.0, 3.0.1)", + org.springframework.dao.*;version="[3.0.0, 3.0.1)", + org.springframework.instrument.classloading.*;version="[3.0.0, 3.0.1)";resolution:=optional, + org.springframework.jdbc.*;version="[3.0.0, 3.0.1)", + org.springframework.jndi.*;version="[3.0.0, 3.0.1)";resolution:=optional, + org.springframework.transaction.*;version="[3.0.0, 3.0.1)", + org.springframework.util.*;version="[3.0.0, 3.0.1)", + org.springframework.web.*;version="[3.0.0, 3.0.1)";resolution:=optional, + org.springframework.ui.*;version="[3.0.0, 3.0.1)";resolution:=optional +Unversioned-Imports: + * +Ignored-Existing-Headers: + Bnd-LastModified, + DynamicImport-Package, + Import-Package, + Export-Package, + Tool