SPR-8295 - Extension for CastorMarshaller - additional marshaller properties

This commit is contained in:
Arjen Poutsma 2011-05-19 13:34:36 +00:00
parent 5ac2e4418f
commit dd8a9cce05
1 changed files with 147 additions and 49 deletions

View File

@ -61,8 +61,8 @@ import org.springframework.util.xml.StaxUtils;
/** /**
* Implementation of the <code>Marshaller</code> interface for Castor. By default, Castor does not require any further * Implementation of the <code>Marshaller</code> 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 * configuration, though setting target classes, target packages or providing a mapping file can be used to have more
* behavior of Castor. * control over the behavior of Castor.
* *
* <p>If a target class is specified using <code>setTargetClass</code>, the <code>CastorMarshaller</code> can only be * <p>If a target class is specified using <code>setTargetClass</code>, the <code>CastorMarshaller</code> can only be
* used to unmarshall XML that represents that specific class. If you want to unmarshall multiple classes, you have to * 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 <code>UTF-8</code>. * defaults to <code>UTF-8</code>.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Jakub Narloch
* @see #setEncoding(String) * @see #setEncoding(String)
* @see #setTargetClass(Class) * @see #setTargetClass(Class)
* @see #setTargetPackages(String[]) * @see #setTargetPackages(String[])
@ -86,7 +87,6 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
*/ */
public static final String DEFAULT_ENCODING = "UTF-8"; public static final String DEFAULT_ENCODING = "UTF-8";
private Resource[] mappingLocations; private Resource[] mappingLocations;
private String encoding = DEFAULT_ENCODING; private String encoding = DEFAULT_ENCODING;
@ -111,9 +111,23 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
private boolean suppressXsiType = false; 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<String, String> processingInstructions;
/** /**
* Set the encoding to be used for stream access. * Set the encoding to be used for stream access.
*
* @see #DEFAULT_ENCODING * @see #DEFAULT_ENCODING
*/ */
public void setEncoding(String encoding) { public void setEncoding(String encoding) {
@ -135,18 +149,16 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
} }
/** /**
* Set the Castor target class. Alternative means of configuring * Set the Castor target class. Alternative means of configuring <code>CastorMarshaller<code> for unmarshalling
* <code>CastorMarshaller<code> for unmarshalling multiple classes include * multiple classes include use of mapping files, and specifying packages with Castor descriptor classes.
* use of mapping files, and specifying packages with Castor descriptor classes.
*/ */
public void setTargetClass(Class targetClass) { public void setTargetClass(Class targetClass) {
this.targetClasses = new Class[]{targetClass}; this.targetClasses = new Class[]{targetClass};
} }
/** /**
* Set the Castor target classes. Alternative means of configuring * Set the Castor target classes. Alternative means of configuring <code>CastorMarshaller<code> for unmarshalling
* <code>CastorMarshaller<code> for unmarshalling multiple classes include * multiple classes include use of mapping files, and specifying packages with Castor descriptor classes.
* use of mapping files, and specifying packages with Castor descriptor classes.
*/ */
public void setTargetClasses(Class[] targetClasses) { public void setTargetClasses(Class[] targetClasses) {
this.targetClasses = 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. * Set whether this marshaller should validate in- and outgoing documents. <p>Default is <code>false</code>.
* <p>Default is <code>false</code>. *
* @see Marshaller#setValidation(boolean) * @see Marshaller#setValidation(boolean)
*/ */
public void setValidating(boolean validating) { 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. * Set whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace. <p>Default is
* <p>Default is <code>false</code>. * <code>false</code>.
*
* @see org.exolab.castor.xml.Unmarshaller#setWhitespacePreserve(boolean) * @see org.exolab.castor.xml.Unmarshaller#setWhitespacePreserve(boolean)
*/ */
public void setWhitespacePreserve(boolean whitespacePreserve) { 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. * Set whether the Castor {@link Unmarshaller} should ignore attributes that do not match a specific field. <p>Default
* <p>Default is <code>true</code>: extra attributes are ignored. * is <code>true</code>: extra attributes are ignored.
*
* @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraAttributes(boolean) * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraAttributes(boolean)
*/ */
public void setIgnoreExtraAttributes(boolean ignoreExtraAttributes) { 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. * Set whether the Castor {@link Unmarshaller} should ignore elements that do not match a specific field. <p>Default is
* <p>Default is <code>false</code>, extra attributes are flagged as an error. * <code>false</code>, extra attributes are flagged as an error.
*
* @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraElements(boolean) * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraElements(boolean)
*/ */
public void setIgnoreExtraElements(boolean ignoreExtraElements) { 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. * Set the namespace mappings. Property names are interpreted as namespace prefixes; values are namespace URIs.
*
* @see org.exolab.castor.xml.Marshaller#setNamespaceMapping(String, String) * @see org.exolab.castor.xml.Marshaller#setNamespaceMapping(String, String)
*/ */
public void setNamespaceMappings(Map<String, String> namespaceMappings) { public void setNamespaceMappings(Map<String, String> namespaceMappings) {
this.namespaceMappings = namespaceMappings; this.namespaceMappings = namespaceMappings;
} }
/** Returns whether this marshaller should output namespaces. */ /**
* Returns whether this marshaller should output namespaces.
*/
public boolean isSuppressNamespaces() { public boolean isSuppressNamespaces() {
return suppressNamespaces; return suppressNamespaces;
} }
/** /**
* Sets whether this marshaller should output namespaces. The default is {@code false}, i.e. namespaces are * Sets whether this marshaller should output namespaces. The default is {@code false}, i.e. namespaces are written.
* written.
* *
* @see org.exolab.castor.xml.Marshaller#setSuppressNamespaces(boolean) * @see org.exolab.castor.xml.Marshaller#setSuppressNamespaces(boolean)
*/ */
@ -218,7 +235,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
this.suppressNamespaces = suppressNamespaces; 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() { public boolean isSuppressXsiType() {
return suppressXsiType; return suppressXsiType;
} }
@ -233,6 +252,76 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
this.suppressXsiType = suppressXsiType; this.suppressXsiType = suppressXsiType;
} }
/**
* Sets whether this marshaller should output the xml declaration. </p> 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.</p> 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. </p> 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<String, String> processingInstructions) {
this.processingInstructions = processingInstructions;
}
public final void afterPropertiesSet() throws CastorMappingException, IOException { public final void afterPropertiesSet() throws CastorMappingException, IOException {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
if (!ObjectUtils.isEmpty(this.mappingLocations)) { if (!ObjectUtils.isEmpty(this.mappingLocations)) {
@ -265,9 +354,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
} }
/** /**
* Create the Castor <code>XMLContext</code>. Subclasses can override this to create a custom context. * Create the Castor <code>XMLContext</code>. Subclasses can override this to create a custom context. <p> The default
* <p> * implementation loads mapping files if defined, or the target class or packages if defined.
* The default implementation loads mapping files if defined, or the target class or packages if defined.
* *
* @return the created resolver * @return the created resolver
* @throws MappingException when the mapping file cannot be loaded * @throws MappingException when the mapping file cannot be loaded
@ -351,15 +439,31 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
} }
/** /**
* Template method that allows for customizing of the given Castor {@link Marshaller}. * Template method that allows for customizing of the given Castor {@link Marshaller}. </p>The default implementation
* <p>The default implementation invokes {@link Marshaller#setValidation(boolean)} * invokes {@link Marshaller#setValidation(boolean)}, {@link Marshaller#setSuppressNamespaces(boolean)}, {@link
* with the property set on this marshaller, and calls {@link Marshaller#setNamespaceMapping(String, String)} * Marshaller#setSuppressXSIType(boolean)}, {@link Marshaller#setMarshalAsDocument(boolean)}, {@link
* with the {@linkplain #setNamespaceMappings(java.util.Map) namespace mappings}. * 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) { protected void customizeMarshaller(Marshaller marshaller) {
marshaller.setValidation(this.validating); marshaller.setValidation(this.validating);
marshaller.setSuppressNamespaces(isSuppressNamespaces()); marshaller.setSuppressNamespaces(isSuppressNamespaces());
marshaller.setSuppressXSIType(isSuppressXsiType()); 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<String, String> processingInstruction : processingInstructions.entrySet()) {
marshaller.addProcessingInstruction(processingInstruction.getKey(), processingInstruction.getValue());
}
}
if (this.namespaceMappings != null) { if (this.namespaceMappings != null) {
for (Map.Entry<String, String> entry : namespaceMappings.entrySet()) { for (Map.Entry<String, String> entry : namespaceMappings.entrySet()) {
marshaller.setNamespaceMapping(entry.getKey(), entry.getValue()); marshaller.setNamespaceMapping(entry.getKey(), entry.getValue());
@ -367,7 +471,6 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
} }
} }
// Unmarshalling // Unmarshalling
@Override @Override
@ -445,15 +548,13 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
} }
/** /**
* Template method that allows for customizing of the given Castor * Template method that allows for customizing of the given Castor {@link Unmarshaller}. </p> The default
* {@link Unmarshaller}. * implementation invokes {@link Unmarshaller#setValidation(boolean)}, {@link Unmarshaller#setWhitespacePreserve(boolean)},
* <p> * {@link Unmarshaller#setIgnoreExtraAttributes(boolean)}, {@link Unmarshaller#setIgnoreExtraElements(boolean)}, {@link
* The default implementation invokes * Unmarshaller#setClassLoader(ClassLoader)}, {@link Unmarshaller#setObject(Object)}, {@link
* {@link Unmarshaller#setValidation(boolean)}, * Unmarshaller#setReuseObjects(boolean)} and {@link Unmarshaller#setClearCollections(boolean)} with the properties set
* {@link Unmarshaller#setWhitespacePreserve(boolean)}, * on this marshaller, it also calls {@link Unmarshaller#addNamespaceToPackageMapping(String, String)} with the
* {@link Unmarshaller#setIgnoreExtraAttributes(boolean)}, and * {@linkplain #setNamespaceMappings(java.util.Map) namespace to package mapping}.
* {@link Unmarshaller#setIgnoreExtraElements(boolean)} with the properties
* set on this marshaller.
*/ */
protected void customizeUnmarshaller(Unmarshaller unmarshaller) { protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
unmarshaller.setValidation(this.validating); unmarshaller.setValidation(this.validating);
@ -463,16 +564,13 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
} }
/** /**
* Convert the given <code>XMLException</code> to an appropriate exception * Convert the given <code>XMLException</code> to an appropriate exception from the
* from the <code>org.springframework.oxm</code> hierarchy. * <code>org.springframework.oxm</code> hierarchy. <p> A boolean flag is used to indicate whether this exception occurs
* <p> * during marshalling or unmarshalling, since Castor itself does not make this distinction in its exception 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</code> that occured * @param ex Castor <code>XMLException</code> that occured
* @param marshalling indicates whether the exception occurs during * @param marshalling indicates whether the exception occurs during marshalling (<code>true</code>), or unmarshalling
* marshalling (<code>true</code>), or unmarshalling (<code>false</code>) * (<code>false</code>)
* @return the corresponding <code>XmlMappingException</code> * @return the corresponding <code>XmlMappingException</code>
*/ */
protected XmlMappingException convertCastorException(XMLException ex, boolean marshalling) { protected XmlMappingException convertCastorException(XMLException ex, boolean marshalling) {