/*
* Copyright 2002-2018 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.Map;
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.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;
import org.xml.sax.ext.LexicalHandler;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.oxm.MarshallingFailureException;
import org.springframework.oxm.UncategorizedMappingException;
import org.springframework.oxm.UnmarshallingFailureException;
import org.springframework.oxm.ValidationFailureException;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.oxm.support.SaxResourceUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.xml.DomUtils;
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. If a target class is specified using setTargetClass
, the 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 setMappingLocations
.
Due to limitations of Castor's API, it is required to set the encoding used for writing to output streams. It defaults to UTF-8
.
Author: Arjen Poutsma, Jakub Narloch, Juergen Hoeller See Also: Since: 3.0 Deprecated: as of Spring Framework 4.3.13, due to the lack of activity on the Castor project
/**
* 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.
*
* <p>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}.
*
* <p>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[])
* @deprecated as of Spring Framework 4.3.13, due to the lack of activity on the Castor project
*/
@Deprecated
public class CastorMarshaller extends AbstractMarshaller implements InitializingBean, BeanClassLoaderAware {
The default encoding used for stream access: UTF-8.
/**
* The default encoding used for stream access: UTF-8.
*/
public static final String DEFAULT_ENCODING = "UTF-8";
@Nullable
private Resource[] mappingLocations;
private String encoding = DEFAULT_ENCODING;
@Nullable
private Class<?>[] targetClasses;
@Nullable
private String[] targetPackages;
private boolean validating = false;
private boolean suppressNamespaces = false;
private boolean suppressXsiType = false;
private boolean marshalAsDocument = true;
private boolean marshalExtendedType = true;
@Nullable
private String rootElement;
@Nullable
private String noNamespaceSchemaLocation;
@Nullable
private String schemaLocation;
private boolean useXSITypeAtRoot = false;
private boolean whitespacePreserve = false;
private boolean ignoreExtraAttributes = true;
private boolean ignoreExtraElements = false;
@Nullable
private Object rootObject;
private boolean reuseObjects = false;
private boolean clearCollections = false;
@Nullable
private Map<String, String> castorProperties;
@Nullable
private Map<String, String> doctypes;
@Nullable
private Map<String, String> processingInstructions;
@Nullable
private Map<String, String> namespaceMappings;
@Nullable
private Map<String, String> namespaceToPackageMapping;
@Nullable
private EntityResolver entityResolver;
@Nullable
private XMLClassDescriptorResolver classDescriptorResolver;
@Nullable
private IDResolver idResolver;
@Nullable
private ObjectFactory objectFactory;
@Nullable
private ClassLoader beanClassLoader;
@Nullable
private XMLContext xmlContext;
Set the encoding to be used for stream access.
See Also: - DEFAULT_ENCODING
/**
* Set the encoding to be used for stream access.
* @see #DEFAULT_ENCODING
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
@Override
protected String getDefaultEncoding() {
return this.encoding;
}
Set the locations of the Castor XML mapping files.
/**
* Set the locations of the Castor XML mapping files.
*/
public void setMappingLocation(Resource mappingLocation) {
this.mappingLocations = new Resource[]{mappingLocation};
}
Set the locations of the Castor XML mapping files.
/**
* Set the locations of the Castor XML mapping files.
*/
public void setMappingLocations(Resource... mappingLocations) {
this.mappingLocations = mappingLocations;
}
Set the Castor target class.
See Also: - setTargetPackage
- setMappingLocation
/**
* Set the Castor target class.
* @see #setTargetPackage
* @see #setMappingLocation
*/
public void setTargetClass(Class<?> targetClass) {
this.targetClasses = new Class<?>[] {targetClass};
}
Set the Castor target classes.
See Also: - setTargetPackages
- setMappingLocations
/**
* Set the Castor target classes.
* @see #setTargetPackages
* @see #setMappingLocations
*/
public void setTargetClasses(Class<?>... targetClasses) {
this.targetClasses = targetClasses;
}
Set the name of a package with the Castor descriptor classes.
/**
* Set the name of a package with the Castor descriptor classes.
*/
public void setTargetPackage(String targetPackage) {
this.targetPackages = new String[] {targetPackage};
}
Set the names of packages with the Castor descriptor classes.
/**
* Set the names of packages with the Castor descriptor classes.
*/
public void setTargetPackages(String... targetPackages) {
this.targetPackages = targetPackages;
}
Set whether this marshaller should validate in- and outgoing documents.
Default is false
.
See Also:
/**
* Set whether this marshaller should validate in- and outgoing documents.
* <p>Default is {@code false}.
* @see Marshaller#setValidation(boolean)
*/
public void setValidating(boolean validating) {
this.validating = validating;
}
Sets whether this marshaller should output namespaces.
The default is false
, i.e. namespaces are written.
See Also:
/**
* Sets whether this marshaller should output namespaces.
* <p>The default is {@code false}, i.e. namespaces are written.
* @see org.exolab.castor.xml.Marshaller#setSuppressNamespaces(boolean)
*/
public void setSuppressNamespaces(boolean suppressNamespaces) {
this.suppressNamespaces = suppressNamespaces;
}
Set whether this marshaller should output the xsi:type
attribute. The default is false
, i.e. the xsi:type
is written.
See Also:
/**
* Set whether this marshaller should output the {@code xsi:type} attribute.
* <p>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) {
this.suppressXsiType = suppressXsiType;
}
Set whether this marshaller should output the xml declaration.
The default is true
, the XML declaration will be written.
See Also:
/**
* Set 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;
}
Set whether this marshaller should output for given type the xsi:type
attribute. The default is true
, the xsi:type
attribute will be written.
See Also:
/**
* Set 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;
}
Set the name of the root element.
See Also: - setRootElement.setRootElement(String)
/**
* 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 xsi:noNamespaceSchemaLocation
attribute. When set, the xsi:noNamespaceSchemaLocation
attribute will be written for the root element. See Also:
/**
* 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) {
this.noNamespaceSchemaLocation = noNamespaceSchemaLocation;
}
Set the value of xsi:schemaLocation
attribute. When set, the xsi:schemaLocation
attribute will be written for the root element. See Also:
/**
* 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) {
this.schemaLocation = schemaLocation;
}
Sets whether this marshaller should output the 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 false
: The xsi:type
attribute for the root element won't be written.
See Also:
/**
* 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;
}
Set whether the Castor Unmarshaller
should preserve "ignorable" whitespace. Default is false
.
See Also:
/**
* Set whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace.
* <p>Default is {@code false}.
* @see org.exolab.castor.xml.Unmarshaller#setWhitespacePreserve(boolean)
*/
public void setWhitespacePreserve(boolean whitespacePreserve) {
this.whitespacePreserve = whitespacePreserve;
}
Set whether the Castor Unmarshaller
should ignore attributes that do not match a specific field. Default is true
: Extra attributes are ignored.
See Also:
/**
* Set whether the Castor {@link Unmarshaller} should ignore attributes that do not match a specific field.
* <p>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 Unmarshaller
should ignore elements that do not match a specific field. Default is false
: Extra elements are flagged as an error.
See Also:
/**
* Set whether the Castor {@link Unmarshaller} should ignore elements that do not match a specific field.
* <p>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 Also: - setObject.setObject(Object)
/**
* 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 setRootObject(Object root) {
this.rootObject = root;
}
Set whether this unmarshaller should re-use objects.
This will be only used when unmarshalling to an existing object.
The default is false
, which means that the objects won't be re-used.
See Also:
/**
* Set whether this unmarshaller should re-use objects.
* This will be only used when unmarshalling to an existing object.
* <p>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) {
this.reuseObjects = reuseObjects;
}
Sets whether this unmarshaller should clear collections upon the first use.
The default is false
which means that marshaller won't clear collections.
See Also:
/**
* Sets whether this unmarshaller should clear collections upon the first use.
* <p>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;
}
Set Castor-specific properties for marshalling and unmarshalling.
Each entry key is considered the property name and each value the property value.
See Also: - setProperty.setProperty(String, String)
- Unmarshaller.setProperty(String, String)
/**
* 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<String, String> castorProperties) {
this.castorProperties = castorProperties;
}
Set the map containing document type definition for the marshaller.
Each entry has system id as key and public id as value.
See Also: - setDoctype.setDoctype(String, String)
/**
* Set the map containing document type definition for the marshaller.
* Each entry has system id as key and public id as value.
* @see org.exolab.castor.xml.Marshaller#setDoctype(String, String)
*/
public void setDoctypes(Map<String, String> doctypes) {
this.doctypes = doctypes;
}
Sets the processing instructions that will be used by during marshalling.
Keys are the processing targets and values contain the processing data.
See Also: - addProcessingInstruction.addProcessingInstruction(String, String)
/**
* 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;
}
Set the namespace mappings.
Property names are interpreted as namespace prefixes; values are namespace URIs.
See Also: - setNamespaceMapping.setNamespaceMapping(String, String)
/**
* 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<String, String> namespaceMappings) {
this.namespaceMappings = namespaceMappings;
}
Set the namespace to package mappings. Property names are represents the namespaces URI, values are packages.
See Also: - setNamespaceMapping.setNamespaceMapping(String, String)
/**
* Set the namespace to package mappings. Property names are represents the namespaces URI, values are packages.
* @see org.exolab.castor.xml.Marshaller#setNamespaceMapping(String, String)
*/
public void setNamespaceToPackageMapping(Map<String, String> namespaceToPackageMapping) {
this.namespaceToPackageMapping = namespaceToPackageMapping;
}
Set the EntityResolver
to be used during unmarshalling. This resolver will used to resolve system and public ids. See Also:
/**
* Set the {@link EntityResolver} to be used during unmarshalling.
* This resolver will used to resolve system and public ids.
* @see org.exolab.castor.xml.Unmarshaller#setEntityResolver(EntityResolver)
*/
public void setEntityResolver(EntityResolver entityResolver) {
this.entityResolver = entityResolver;
}
Set the XMLClassDescriptorResolver
to be used during unmarshalling. This resolver will used to resolve class descriptors. See Also:
/**
* Set the {@link XMLClassDescriptorResolver} to be used during unmarshalling.
* This resolver will used to resolve class descriptors.
* @see org.exolab.castor.xml.Unmarshaller#setResolver(XMLClassDescriptorResolver)
*/
public void setClassDescriptorResolver(XMLClassDescriptorResolver classDescriptorResolver) {
this.classDescriptorResolver = classDescriptorResolver;
}
Set the Castor IDResolver
to be used during unmarshalling. See Also:
/**
* Set the Castor {@link IDResolver} to be used during unmarshalling.
* @see org.exolab.castor.xml.Unmarshaller#setIDResolver(IDResolver)
*/
public void setIdResolver(IDResolver idResolver) {
this.idResolver = idResolver;
}
Set the Castor ObjectFactory
to be used during unmarshalling. See Also:
/**
* Set the Castor {@link ObjectFactory} to be used during unmarshalling.
* @see org.exolab.castor.xml.Unmarshaller#setObjectFactory(ObjectFactory)
*/
public void setObjectFactory(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
@Override
public void afterPropertiesSet() throws CastorMappingException, IOException {
try {
this.xmlContext = createXMLContext(this.mappingLocations, this.targetClasses, this.targetPackages);
}
catch (MappingException ex) {
throw new CastorMappingException("Could not load Castor mapping", ex);
}
catch (ResolverException ex) {
throw new CastorMappingException("Could not resolve Castor mapping", ex);
}
}
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.
Throws: - MappingException – when the mapping file cannot be loaded
- IOException – in case of I/O errors
See Also: Returns: the created resolver
/**
* Create the Castor {@code XMLContext}. Subclasses can override this to create a custom context.
* <p>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
* @see XMLContext#addMapping(org.exolab.castor.mapping.Mapping)
* @see XMLContext#addClass(Class)
*/
protected XMLContext createXMLContext(@Nullable Resource[] mappingLocations,
@Nullable Class<?>[] targetClasses, @Nullable String[] targetPackages)
throws MappingException, ResolverException, IOException {
XMLContext context = new XMLContext();
if (!ObjectUtils.isEmpty(mappingLocations)) {
Mapping mapping = new Mapping();
for (Resource mappingLocation : mappingLocations) {
mapping.loadMapping(SaxResourceUtils.createInputSource(mappingLocation));
}
context.addMapping(mapping);
}
if (!ObjectUtils.isEmpty(targetClasses)) {
context.addClasses(targetClasses);
}
if (!ObjectUtils.isEmpty(targetPackages)) {
context.addPackages(targetPackages);
}
if (this.castorProperties != null) {
this.castorProperties.forEach(context::setProperty);
}
return context;
}
Returns true
for all classes, i.e. Castor supports arbitrary classes. /**
* Returns {@code true} for all classes, i.e. Castor supports arbitrary classes.
*/
@Override
public boolean supports(Class<?> clazz) {
return true;
}
// Marshalling
@Override
protected void marshalDomNode(Object graph, Node node) throws XmlMappingException {
marshalSaxHandlers(graph, DomUtils.createContentHandler(node), null);
}
@Override
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
LexicalHandler lexicalHandler = null;
if (contentHandler instanceof LexicalHandler) {
lexicalHandler = (LexicalHandler) contentHandler;
}
marshalSaxHandlers(graph, contentHandler, lexicalHandler);
}
@Override
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
ContentHandler contentHandler = StaxUtils.createContentHandler(streamWriter);
LexicalHandler lexicalHandler = null;
if (contentHandler instanceof LexicalHandler) {
lexicalHandler = (LexicalHandler) contentHandler;
}
marshalSaxHandlers(graph, StaxUtils.createContentHandler(streamWriter), lexicalHandler);
}
@Override
protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, @Nullable LexicalHandler lexicalHandler)
throws XmlMappingException {
Assert.state(this.xmlContext != null, "CastorMarshaller not initialized");
Marshaller marshaller = this.xmlContext.createMarshaller();
marshaller.setContentHandler(contentHandler);
doMarshal(graph, marshaller);
}
@Override
protected void marshalOutputStream(Object graph, OutputStream outputStream) throws XmlMappingException, IOException {
marshalWriter(graph, new OutputStreamWriter(outputStream, this.encoding));
}
@Override
protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
Assert.state(this.xmlContext != null, "CastorMarshaller not initialized");
Marshaller marshaller = this.xmlContext.createMarshaller();
marshaller.setWriter(writer);
doMarshal(graph, marshaller);
}
private void doMarshal(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 Marshaller
. /**
* Template method that allows for customizing of the given Castor {@link Marshaller}.
*/
protected void customizeMarshaller(Marshaller marshaller) {
marshaller.setValidation(this.validating);
marshaller.setSuppressNamespaces(this.suppressNamespaces);
marshaller.setSuppressXSIType(this.suppressXsiType);
marshaller.setMarshalAsDocument(this.marshalAsDocument);
marshaller.setMarshalExtendedType(this.marshalExtendedType);
marshaller.setRootElement(this.rootElement);
marshaller.setNoNamespaceSchemaLocation(this.noNamespaceSchemaLocation);
marshaller.setSchemaLocation(this.schemaLocation);
marshaller.setUseXSITypeAtRoot(this.useXSITypeAtRoot);
if (this.doctypes != null) {
this.doctypes.forEach(marshaller::setDoctype);
}
if (this.processingInstructions != null) {
this.processingInstructions.forEach(marshaller::addProcessingInstruction);
}
if (this.namespaceMappings != null) {
this.namespaceMappings.forEach(marshaller::setNamespaceMapping);
}
}
// Unmarshalling
@Override
protected Object unmarshalDomNode(Node node) throws XmlMappingException {
try {
return createUnmarshaller().unmarshal(node);
}
catch (XMLException ex) {
throw convertCastorException(ex, false);
}
}
@Override
protected Object unmarshalXmlEventReader(XMLEventReader eventReader) {
try {
return createUnmarshaller().unmarshal(eventReader);
}
catch (XMLException ex) {
throw convertCastorException(ex, false);
}
}
@Override
protected Object unmarshalXmlStreamReader(XMLStreamReader streamReader) {
try {
return createUnmarshaller().unmarshal(streamReader);
}
catch (XMLException ex) {
throw convertCastorException(ex, false);
}
}
@Override
protected 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 UnmarshallingFailureException("SAX reader exception", ex);
}
}
@Override
protected Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException {
try {
return createUnmarshaller().unmarshal(new InputSource(inputStream));
}
catch (XMLException ex) {
throw convertCastorException(ex, false);
}
}
@Override
protected Object unmarshalReader(Reader reader) throws XmlMappingException, IOException {
try {
return createUnmarshaller().unmarshal(new InputSource(reader));
}
catch (XMLException ex) {
throw convertCastorException(ex, false);
}
}
private Unmarshaller createUnmarshaller() {
Assert.state(this.xmlContext != null, "CastorMarshaller not initialized");
Unmarshaller unmarshaller = this.xmlContext.createUnmarshaller();
customizeUnmarshaller(unmarshaller);
return unmarshaller;
}
Template method that allows for customizing of the given Castor Unmarshaller
. /**
* Template method that allows for customizing of the given Castor {@link Unmarshaller}.
*/
protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
unmarshaller.setValidation(this.validating);
unmarshaller.setWhitespacePreserve(this.whitespacePreserve);
unmarshaller.setIgnoreExtraAttributes(this.ignoreExtraAttributes);
unmarshaller.setIgnoreExtraElements(this.ignoreExtraElements);
unmarshaller.setObject(this.rootObject);
unmarshaller.setReuseObjects(this.reuseObjects);
unmarshaller.setClearCollections(this.clearCollections);
if (this.namespaceToPackageMapping != null) {
this.namespaceToPackageMapping.forEach(unmarshaller::addNamespaceToPackageMapping);
}
if (this.entityResolver != null) {
unmarshaller.setEntityResolver(this.entityResolver);
}
if (this.classDescriptorResolver != null) {
unmarshaller.setResolver(this.classDescriptorResolver);
}
if (this.idResolver != null) {
unmarshaller.setIDResolver(this.idResolver);
}
if (this.objectFactory != null) {
unmarshaller.setObjectFactory(this.objectFactory);
}
if (this.beanClassLoader != null) {
unmarshaller.setClassLoader(this.beanClassLoader);
}
}
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.
Params: - ex – the Castor
XMLException
that occurred - marshalling – indicates whether the exception occurs during marshalling (
true
), or unmarshalling (false
)
Returns: the corresponding XmlMappingException
/**
* Convert the given {@code XMLException} to an appropriate exception from the
* {@code org.springframework.oxm} hierarchy.
* <p>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 the Castor {@code XMLException} that occurred
* @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) {
if (ex instanceof ValidationException) {
return new ValidationFailureException("Castor validation exception", ex);
}
else if (ex instanceof MarshalException) {
if (marshalling) {
return new MarshallingFailureException("Castor marshalling exception", ex);
}
else {
return new UnmarshallingFailureException("Castor unmarshalling exception", ex);
}
}
else {
// fallback
return new UncategorizedMappingException("Unknown Castor exception", ex);
}
}
}