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 index 871075f2362..10a83faee5b 100644 --- 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 @@ -61,8 +61,8 @@ import org.springframework.util.xml.StaxUtils; /** * Implementation of the 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. + * 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 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 @@ -72,6 +72,7 @@ import org.springframework.util.xml.StaxUtils; * defaults to UTF-8. * * @author Arjen Poutsma + * @author Jakub Narloch * @see #setEncoding(String) * @see #setTargetClass(Class) * @see #setTargetPackages(String[]) @@ -86,7 +87,6 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing */ public static final String DEFAULT_ENCODING = "UTF-8"; - private Resource[] mappingLocations; private String encoding = DEFAULT_ENCODING; @@ -111,9 +111,23 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing private boolean suppressXsiType = false; + private boolean marshalAsDocument = true; + + private String rootElement; + + private boolean marshalExtendedType = true; + + private String noNamespaceSchemaLocation; + + private String schemaLocation; + + private boolean useXSITypeAtRoot = false; + + private Map processingInstructions; /** * Set the encoding to be used for stream access. + * * @see #DEFAULT_ENCODING */ public void setEncoding(String encoding) { @@ -124,7 +138,7 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing * Set the locations of the Castor XML Mapping files. */ public void setMappingLocation(Resource mappingLocation) { - this.mappingLocations = new Resource[] {mappingLocation}; + this.mappingLocations = new Resource[]{mappingLocation}; } /** @@ -135,18 +149,16 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Set the Castor target class. Alternative means of configuring - * CastorMarshaller for unmarshalling multiple classes include - * use of mapping files, and specifying packages with Castor descriptor classes. + * Set the Castor target class. Alternative means of configuring CastorMarshaller for unmarshalling + * multiple classes include use of mapping files, and specifying packages with Castor descriptor classes. */ public void setTargetClass(Class targetClass) { this.targetClasses = new Class[]{targetClass}; } /** - * Set the Castor target classes. Alternative means of configuring - * CastorMarshaller for unmarshalling multiple classes include - * use of mapping files, and specifying packages with Castor descriptor classes. + * Set the Castor target classes. Alternative means of configuring CastorMarshaller for unmarshalling + * multiple classes include use of mapping files, and specifying packages with Castor descriptor classes. */ public void setTargetClasses(Class[] targetClasses) { this.targetClasses = targetClasses; @@ -160,8 +172,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Set whether this marshaller should validate in- and outgoing documents. - *

Default is false. + * Set whether this marshaller should validate in- and outgoing documents.

Default is false. + * * @see Marshaller#setValidation(boolean) */ public void setValidating(boolean validating) { @@ -169,8 +181,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Set whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace. - *

Default is false. + * Set 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) { @@ -178,8 +191,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Set whether the Castor {@link Unmarshaller} should ignore attributes that do not match a specific field. - *

Default is true: extra attributes are ignored. + * Set 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) { @@ -187,8 +201,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Set 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. + * Set 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) { @@ -197,20 +212,22 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing /** * 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 namespaceMappings) { this.namespaceMappings = namespaceMappings; } - /** Returns whether this marshaller should output namespaces. */ + /** + * Returns whether this marshaller should output namespaces. + */ public boolean isSuppressNamespaces() { return suppressNamespaces; } /** - * Sets whether this marshaller should output namespaces. The default is {@code false}, i.e. namespaces are - * written. + * Sets whether this marshaller should output namespaces. The default is {@code false}, i.e. namespaces are written. * * @see org.exolab.castor.xml.Marshaller#setSuppressNamespaces(boolean) */ @@ -218,7 +235,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing this.suppressNamespaces = suppressNamespaces; } - /** Sets whether this marshaller should output the xsi:type attribute. */ + /** + * Sets whether this marshaller should output the xsi:type attribute. + */ public boolean isSuppressXsiType() { return suppressXsiType; } @@ -233,6 +252,76 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing this.suppressXsiType = suppressXsiType; } + /** + * 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) { + this.marshalAsDocument = marshalAsDocument; + } + + /** + * 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) { + this.marshalExtendedType = marshalExtendedType; + } + + /** + * Sets 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) { + this.noNamespaceSchemaLocation = noNamespaceSchemaLocation; + } + + /** + * Sets 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) { + this.schemaLocation = schemaLocation; + } + + /** + * 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) { + this.useXSITypeAtRoot = useXSITypeAtRoot; + } + + /** + * 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) + */ + public void setProcessingInstructions(Map processingInstructions) { + this.processingInstructions = processingInstructions; + } + public final void afterPropertiesSet() throws CastorMappingException, IOException { if (logger.isInfoEnabled()) { if (!ObjectUtils.isEmpty(this.mappingLocations)) { @@ -265,13 +354,12 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Create the Castor 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. + * Create the Castor 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 + * @throws IOException in case of I/O errors * @see XMLContext#addMapping(org.exolab.castor.mapping.Mapping) * @see XMLContext#addClass(Class) */ @@ -351,15 +439,31 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Template method that allows for customizing of the given Castor {@link Marshaller}. - *

The 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.Map) namespace mappings}. + * Template method that allows for customizing of the given Castor {@link Marshaller}.

The default implementation + * invokes {@link Marshaller#setValidation(boolean)}, {@link Marshaller#setSuppressNamespaces(boolean)}, {@link + * Marshaller#setSuppressXSIType(boolean)}, {@link Marshaller#setMarshalAsDocument(boolean)}, {@link + * Marshaller#setRootElement(String)}, {@link Marshaller#setMarshalExtendedType(boolean)}, {@link + * Marshaller#setNoNamespaceSchemaLocation(String)}, {@link Marshaller#setSchemaLocation(String)} and {@link + * Marshaller#setUseXSITypeAtRoot(boolean)}, 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 processingInstruction : processingInstructions.entrySet()) { + marshaller.addProcessingInstruction(processingInstruction.getKey(), processingInstruction.getValue()); + } + } if (this.namespaceMappings != null) { for (Map.Entry entry : namespaceMappings.entrySet()) { marshaller.setNamespaceMapping(entry.getKey(), entry.getValue()); @@ -367,7 +471,6 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } } - // Unmarshalling @Override @@ -445,15 +548,13 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Template method that allows for customizing of the given Castor - * {@link Unmarshaller}. - *

- * The 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. + * Template method that allows for customizing of the given Castor {@link Unmarshaller}.

The default + * implementation invokes {@link Unmarshaller#setValidation(boolean)}, {@link Unmarshaller#setWhitespacePreserve(boolean)}, + * {@link Unmarshaller#setIgnoreExtraAttributes(boolean)}, {@link Unmarshaller#setIgnoreExtraElements(boolean)}, {@link + * Unmarshaller#setClassLoader(ClassLoader)}, {@link Unmarshaller#setObject(Object)}, {@link + * Unmarshaller#setReuseObjects(boolean)} and {@link Unmarshaller#setClearCollections(boolean)} 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); @@ -463,16 +564,13 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } /** - * Convert 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. + * Convert 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) + * @param ex Castor XMLException that occured + * @param marshalling indicates whether the exception occurs during marshalling (true), or unmarshalling + * (false) * @return the corresponding XmlMappingException */ protected XmlMappingException convertCastorException(XMLException ex, boolean marshalling) {