diff --git a/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java index 0405e8272e..131b782c87 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -30,16 +30,20 @@ import javax.xml.stream.XMLStreamWriter; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.mapping.MappingException; +import org.exolab.castor.util.ObjectFactory; +import org.exolab.castor.xml.IDResolver; 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.ValidationException; +import org.exolab.castor.xml.XMLClassDescriptorResolver; 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.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -56,30 +60,30 @@ import org.springframework.oxm.XmlMappingException; import org.springframework.oxm.support.AbstractMarshaller; import org.springframework.oxm.support.SaxResourceUtils; import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.springframework.util.xml.StaxUtils; /** - * Implementation of the {@code Marshaller} interface for Castor. By default, Castor does not require any further - * configuration, though setting target classes, target packages or providing a mapping file can be used to have more - * control over the behavior of Castor. + * Implementation of the {@code Marshaller} interface for Castor. By default, Castor does + * not require any further configuration, though setting target classes, target packages or + * providing a mapping file can be used to have more control over the behavior of Castor. * - *
If a target class is specified using {@code setTargetClass}, the {@code CastorMarshaller} can only be - * used to unmarshal XML that represents that specific class. If you want to unmarshal multiple classes, you have to - * provide a mapping file using {@code setMappingLocations}. + *
If a target class is specified using {@code setTargetClass}, the {@code CastorMarshaller} + * can only be used to unmarshal XML that represents that specific class. If you want to unmarshal + * multiple classes, you have to provide a mapping file using {@code setMappingLocations}. * - *
Due to limitations of Castor's API, it is required to set the encoding used for writing to output streams. It - * defaults to {@code UTF-8}. + *
Due to limitations of Castor's API, it is required to set the encoding used for
+ * writing to output streams. It defaults to {@code UTF-8}.
*
* @author Arjen Poutsma
* @author Jakub Narloch
+ * @author Juergen Hoeller
+ * @since 3.0
* @see #setEncoding(String)
* @see #setTargetClass(Class)
* @see #setTargetPackages(String[])
* @see #setMappingLocation(Resource)
* @see #setMappingLocations(Resource[])
- * @since 3.0
*/
public class CastorMarshaller extends AbstractMarshaller implements InitializingBean, BeanClassLoaderAware {
@@ -88,6 +92,7 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
*/
public static final String DEFAULT_ENCODING = "UTF-8";
+
private Resource[] mappingLocations;
private String encoding = DEFAULT_ENCODING;
@@ -98,47 +103,59 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
private boolean validating = false;
- private boolean whitespacePreserve = false;
-
- private boolean ignoreExtraAttributes = true;
-
- private boolean ignoreExtraElements = false;
-
- private Map Default is {@code false}.
- *
+ * Set whether this marshaller should validate in- and outgoing documents.
+ * Default is {@code false}.
* @see Marshaller#setValidation(boolean)
*/
public void setValidating(boolean validating) {
@@ -199,55 +216,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Set whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace. Default is
- * {@code false}.
- *
- * @see org.exolab.castor.xml.Unmarshaller#setWhitespacePreserve(boolean)
- */
- public void setWhitespacePreserve(boolean whitespacePreserve) {
- this.whitespacePreserve = whitespacePreserve;
- }
-
- /**
- * Set whether the Castor {@link Unmarshaller} should ignore attributes that do not match a specific field. Default
- * is {@code true}: extra attributes are ignored.
- *
- * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraAttributes(boolean)
- */
- public void setIgnoreExtraAttributes(boolean ignoreExtraAttributes) {
- this.ignoreExtraAttributes = ignoreExtraAttributes;
- }
-
- /**
- * Set whether the Castor {@link Unmarshaller} should ignore elements that do not match a specific field. Default
- * is
- * {@code false}, extra attributes are flagged as an error.
- *
- * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraElements(boolean)
- */
- public void setIgnoreExtraElements(boolean ignoreExtraElements) {
- this.ignoreExtraElements = ignoreExtraElements;
- }
-
- /**
- * Set 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(Map The default is {@code false}, i.e. namespaces are written.
* @see org.exolab.castor.xml.Marshaller#setSuppressNamespaces(boolean)
*/
public void setSuppressNamespaces(boolean suppressNamespaces) {
@@ -255,16 +225,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets whether this marshaller should output the xsi:type attribute.
- */
- public boolean isSuppressXsiType() {
- return suppressXsiType;
- }
-
- /**
- * Sets whether this marshaller should output the {@code xsi:type} attribute. The default is {@code false}, i.e. the
- * {@code xsi:type} is written.
- *
+ * Set whether this marshaller should output the {@code xsi:type} attribute.
+ * The default is {@code false}, i.e. the {@code xsi:type} is written.
* @see org.exolab.castor.xml.Marshaller#setSuppressXSIType(boolean)
*/
public void setSuppressXsiType(boolean suppressXsiType) {
@@ -272,9 +234,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets whether this marshaller should output the xml declaration. The default is {@code true}, the XML declaration will be written.
* @see org.exolab.castor.xml.Marshaller#setMarshalAsDocument(boolean)
*/
public void setMarshalAsDocument(boolean marshalAsDocument) {
@@ -282,18 +243,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets the name of the root element.
- *
- * @see org.exolab.castor.xml.Marshaller#setRootElement(String)
- */
- public void setRootElement(String rootElement) {
- this.rootElement = rootElement;
- }
-
- /**
- * Sets whether this marshaller should output for given type the {@code xsi:type} attribute. The default is {@code true}, the {@code xsi:type} attribute will be written.
* @see org.exolab.castor.xml.Marshaller#setMarshalExtendedType(boolean)
*/
public void setMarshalExtendedType(boolean marshalExtendedType) {
@@ -301,9 +252,16 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets the value of {@code xsi:noNamespaceSchemaLocation} attribute. When set, the {@code
- * xsi:noNamespaceSchemaLocation} attribute will be written for the root element.
- *
+ * Set the name of the root element.
+ * @see org.exolab.castor.xml.Marshaller#setRootElement(String)
+ */
+ public void setRootElement(String rootElement) {
+ this.rootElement = rootElement;
+ }
+
+ /**
+ * Set the value of {@code xsi:noNamespaceSchemaLocation} attribute. When set, the
+ * {@code xsi:noNamespaceSchemaLocation} attribute will be written for the root element.
* @see org.exolab.castor.xml.Marshaller#setNoNamespaceSchemaLocation(String)
*/
public void setNoNamespaceSchemaLocation(String noNamespaceSchemaLocation) {
@@ -311,9 +269,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets the value of {@code xsi:schemaLocation} attribute.When set, the {@code xsi:schemaLocation} attribute will be
- * written for the root element.
- *
+ * Set the value of {@code xsi:schemaLocation} attribute. When set, the
+ * {@code xsi:schemaLocation} attribute will be written for the root element.
* @see org.exolab.castor.xml.Marshaller#setSchemaLocation(String)
*/
public void setSchemaLocation(String schemaLocation) {
@@ -321,10 +278,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets whether this marshaller should output the {@code xsi:type} attribute for the root element. This can be useful
- * when the type of the element can not be simply determined from the element name. The default is {@code false}: The {@code xsi:type} attribute for the root element won't be written.
* @see org.exolab.castor.xml.Marshaller#setUseXSITypeAtRoot(boolean)
*/
public void setUseXSITypeAtRoot(boolean useXSITypeAtRoot) {
@@ -332,38 +288,54 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets the processing instructions that will be used by during marshalling. Keys are the processing targets and
- * values
- * contain the processing data.
- *
- * @see org.exolab.castor.xml.Marshaller#addProcessingInstruction(String, String)
+ * Set whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace.
+ * Default is {@code false}.
+ * @see org.exolab.castor.xml.Unmarshaller#setWhitespacePreserve(boolean)
*/
- public void setProcessingInstructions(Map Default is {@code true}: Extra attributes are ignored.
+ * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraAttributes(boolean)
*/
- public void setNamespaceToPackageMapping(Map Default is {@code false}: Extra elements are flagged as an error.
+ * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraElements(boolean)
+ */
+ public void setIgnoreExtraElements(boolean ignoreExtraElements) {
+ this.ignoreExtraElements = ignoreExtraElements;
+ }
+
+ /**
+ * Set the expected root object for the unmarshaller, into which the source will be unmarshalled.
+ * @see org.exolab.castor.xml.Unmarshaller#setObject(Object)
+ * @deprecated in favor of {@link #setRootObject}
+ */
+ @Deprecated
+ public void setObject(Object root) {
+ this.rootObject = root;
+ }
+
+ /**
+ * Set the expected root object for the unmarshaller, into which the source will be unmarshalled.
* @see org.exolab.castor.xml.Unmarshaller#setObject(Object)
*/
- public void setObject(Object root) {
- this.root = root;
+ public void setRootObject(Object root) {
+ this.rootObject = root;
}
/**
- * Sets whether this unmarshaller should re-use objects. This will be only used when unmarshalling to existing
- * object. The default is {@code false}, which means that the objects won't be re-used.
* @see org.exolab.castor.xml.Unmarshaller#setReuseObjects(boolean)
*/
public void setReuseObjects(boolean reuseObjects) {
@@ -371,39 +343,99 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
/**
- * Sets whether this unmarshaller should clear collections upon the first use. The default is {@code false} which means that marshaller won't clear collections.
* @see org.exolab.castor.xml.Unmarshaller#setClearCollections(boolean)
*/
public void setClearCollections(boolean clearCollections) {
this.clearCollections = clearCollections;
}
- public void setBeanClassLoader(ClassLoader classLoader) {
- this.classLoader = classLoader;
+ /**
+ * Set Castor-specific properties for marshalling and unmarshalling.
+ * Each entry key is considered the property name and each value the property value.
+ * @see org.exolab.castor.xml.Marshaller#setProperty(String, String)
+ * @see org.exolab.castor.xml.Unmarshaller#setProperty(String, String)
+ */
+ public void setCastorProperties(Map The default
- * implementation loads mapping files if defined, or the target class or packages if defined.
- *
+ * Create the Castor {@code XMLContext}. Subclasses can override this to create a custom context.
+ * The default implementation loads mapping files if defined, or the target class or packages if defined.
* @return the created resolver
* @throws MappingException when the mapping file cannot be loaded
* @throws IOException in case of I/O errors
@@ -442,9 +473,15 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
if (!ObjectUtils.isEmpty(targetPackages)) {
context.addPackages(targetPackages);
}
+ if (this.castorProperties != null) {
+ for (Map.Entry 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.
- *
+ * {@code 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 {@code XMLException} that occurred
- * @param marshalling indicates whether the exception occurs during marshalling ({@code true}), or unmarshalling
- * ({@code false})
+ * @param marshalling indicates whether the exception occurs during marshalling ({@code true}),
+ * or unmarshalling ({@code false})
* @return the corresponding {@code XmlMappingException}
*/
protected XmlMappingException convertCastorException(XMLException ex, boolean marshalling) {
diff --git a/spring-oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTests.java b/spring-oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTests.java
index 367b4aa5c1..585640893b 100644
--- a/spring-oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTests.java
+++ b/spring-oxm/src/test/java/org/springframework/oxm/castor/CastorUnmarshallerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -30,12 +30,9 @@ import org.springframework.oxm.MarshallingException;
import org.springframework.oxm.Unmarshaller;
import static org.hamcrest.CoreMatchers.*;
-
import static org.junit.Assert.*;
/**
- * Tests the {@link CastorMarshaller} class.
- *
* @author Arjen Poutsma
* @author Jakub Narloch
*/
@@ -114,7 +111,6 @@ public class CastorUnmarshallerTests extends AbstractUnmarshallerTests {
@Test
public void testWhitespacePreserveTrue() throws Exception {
-
getCastorUnmarshaller().setWhitespacePreserve(true);
Object result = unmarshalFlights();
testFlights(result);
@@ -122,7 +118,6 @@ public class CastorUnmarshallerTests extends AbstractUnmarshallerTests {
@Test
public void testWhitespacePreserveFalse() throws Exception {
-
getCastorUnmarshaller().setWhitespacePreserve(false);
Object result = unmarshalFlights();
testFlights(result);
@@ -130,7 +125,6 @@ public class CastorUnmarshallerTests extends AbstractUnmarshallerTests {
@Test
public void testIgnoreExtraAttributesTrue() throws Exception {
-
getCastorUnmarshaller().setIgnoreExtraAttributes(true);
Object result = unmarshal(EXTRA_ATTRIBUTES_STRING);
testFlights(result);
@@ -146,7 +140,6 @@ public class CastorUnmarshallerTests extends AbstractUnmarshallerTests {
@Test
@Ignore("Not working yet")
public void testIgnoreExtraElementsTrue() throws Exception {
-
getCastorUnmarshaller().setIgnoreExtraElements(true);
getCastorUnmarshaller().setValidating(false);
Object result = unmarshal(EXTRA_ELEMENTS_STRING);
@@ -161,22 +154,19 @@ public class CastorUnmarshallerTests extends AbstractUnmarshallerTests {
}
@Test
- public void testObject() throws Exception {
-
+ public void testRootObject() throws Exception {
Flights flights = new Flights();
- getCastorUnmarshaller().setObject(flights);
+ getCastorUnmarshaller().setRootObject(flights);
Object result = unmarshalFlights();
-
testFlights(result);
assertSame("Result Flights is different object.", flights, result);
}
@Test
public void testClearCollectionsTrue() throws Exception {
-
Flights flights = new Flights();
flights.setFlight(new Flight[]{new Flight()});
- getCastorUnmarshaller().setObject(flights);
+ getCastorUnmarshaller().setRootObject(flights);
getCastorUnmarshaller().setClearCollections(true);
Object result = unmarshalFlights();
@@ -188,10 +178,9 @@ public class CastorUnmarshallerTests extends AbstractUnmarshallerTests {
@Test
@Ignore("Fails on the builder server for some reason")
public void testClearCollectionsFalse() throws Exception {
-
Flights flights = new Flights();
flights.setFlight(new Flight[]{new Flight(), null});
- getCastorUnmarshaller().setObject(flights);
+ getCastorUnmarshaller().setRootObject(flights);
getCastorUnmarshaller().setClearCollections(false);
Object result = unmarshalFlights();
- *
- * with the property set on this marshaller.
- * It also calls {@link Marshaller#setNamespaceMapping(String, String)}
- * with the {@linkplain #setNamespaceMappings(java.util.Map) namespace mappings} and
- * {@link Marshaller#addProcessingInstruction(String, String)} with the
- * {@linkplain #setProcessingInstructions(java.util.Map) processing instructions}.
*/
protected void customizeMarshaller(Marshaller marshaller) {
marshaller.setValidation(this.validating);
- marshaller.setSuppressNamespaces(isSuppressNamespaces());
- marshaller.setSuppressXSIType(isSuppressXsiType());
- marshaller.setMarshalAsDocument(marshalAsDocument);
- marshaller.setRootElement(rootElement);
- marshaller.setMarshalExtendedType(marshalExtendedType);
- marshaller.setNoNamespaceSchemaLocation(noNamespaceSchemaLocation);
- marshaller.setSchemaLocation(schemaLocation);
- marshaller.setUseXSITypeAtRoot(useXSITypeAtRoot);
- if (processingInstructions != null) {
- for (Map.Entry
- *
- * with the properties set on this marshaller.
- * It also calls {@link Unmarshaller#addNamespaceToPackageMapping(String, String)} with the
- * {@linkplain #setNamespaceMappings(java.util.Map) namespace to package mapping}.
*/
protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
unmarshaller.setValidation(this.validating);
unmarshaller.setWhitespacePreserve(this.whitespacePreserve);
unmarshaller.setIgnoreExtraAttributes(this.ignoreExtraAttributes);
unmarshaller.setIgnoreExtraElements(this.ignoreExtraElements);
- unmarshaller.setClassLoader(classLoader);
- unmarshaller.setObject(root);
- unmarshaller.setReuseObjects(reuseObjects);
- unmarshaller.setClearCollections(clearCollections);
- if (namespaceToPackageMapping != null) {
- for (Map.Entry