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 00000000000..f589a8a8023 Binary files /dev/null and b/org.springframework.oxm/src/test/resources/org/springframework/oxm/jaxb/spring-ws.png differ diff --git a/org.springframework.oxm/src/test/resources/org/springframework/oxm/jibx/binding.xml b/org.springframework.oxm/src/test/resources/org/springframework/oxm/jibx/binding.xml new file mode 100644 index 00000000000..415021ce064 --- /dev/null +++ b/org.springframework.oxm/src/test/resources/org/springframework/oxm/jibx/binding.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + 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