Spring Object/XML Marshalling support providing generic interfaces for converting Java objects to XML and vice versa
Spring OXM provides several support classes and utilities that simplify common marshalling operations, provide base implementations for custom marshallers, and integrate with Spring's resource handling and transformation framework.
Abstract base class that provides common functionality for marshaller implementations. It handles various XML processing formats and provides template methods for subclasses.
public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
// Configuration methods
public void setSupportDtd(boolean supportDtd);
public boolean isSupportDtd();
public void setProcessExternalEntities(boolean processExternalEntities);
public boolean isProcessExternalEntities();
// Template methods for subclasses to implement - DOM
protected abstract void marshalDomNode(Object graph, Node node) throws XmlMappingException;
protected abstract Object unmarshalDomNode(Node node) throws XmlMappingException;
// Template methods for subclasses to implement - StAX
protected abstract void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException;
protected abstract void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException;
protected abstract Object unmarshalXmlEventReader(XMLEventReader eventReader) throws XmlMappingException;
protected abstract Object unmarshalXmlStreamReader(XMLStreamReader streamReader) throws XmlMappingException;
// Template methods for subclasses to implement - SAX
protected abstract void marshalSaxHandlers(Object graph, ContentHandler contentHandler,
LexicalHandler lexicalHandler) throws XmlMappingException;
protected abstract Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
throws XmlMappingException, IOException;
// Template methods for subclasses to implement - Streams
protected abstract void marshalOutputStream(Object graph, OutputStream outputStream)
throws XmlMappingException, IOException;
protected abstract void marshalWriter(Object graph, Writer writer)
throws XmlMappingException, IOException;
protected abstract Object unmarshalInputStream(InputStream inputStream)
throws XmlMappingException, IOException;
protected abstract Object unmarshalReader(Reader reader)
throws XmlMappingException, IOException;
// Utility methods provided by base class
protected Document buildDocument();
protected XMLReader createXmlReader() throws SAXException, ParserConfigurationException;
protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
throws ParserConfigurationException;
protected DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException;
protected SAXParserFactory createSaxParserFactory() throws ParserConfigurationException, SAXException;
protected String getDefaultEncoding();
}import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.oxm.XmlMappingException;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import java.io.*;
public class CustomMarshaller extends AbstractMarshaller {
@Override
public boolean supports(Class<?> clazz) {
return MyCustomClass.class.isAssignableFrom(clazz);
}
@Override
protected void marshalDomNode(Object graph, Node node) throws XmlMappingException {
// Implement DOM-based marshalling
MyCustomClass obj = (MyCustomClass) graph;
// ... marshal to DOM node
}
@Override
protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler,
LexicalHandler lexicalHandler) throws XmlMappingException {
// Implement SAX-based marshalling
MyCustomClass obj = (MyCustomClass) graph;
// ... marshal using SAX handlers
}
@Override
protected void marshalOutputStream(Object graph, OutputStream outputStream)
throws XmlMappingException, IOException {
// Implement stream-based marshalling
MyCustomClass obj = (MyCustomClass) graph;
// ... marshal to output stream
}
@Override
protected void marshalWriter(Object graph, Writer writer)
throws XmlMappingException, IOException {
// Implement writer-based marshalling
MyCustomClass obj = (MyCustomClass) graph;
// ... marshal to writer
}
@Override
protected Object unmarshalDomNode(Node node) throws XmlMappingException {
// Implement DOM-based unmarshalling
// ... unmarshal from DOM node
return new MyCustomClass();
}
@Override
protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
throws XmlMappingException, IOException {
// Implement SAX-based unmarshalling
// ... unmarshal using SAX reader
return new MyCustomClass();
}
@Override
protected Object unmarshalInputStream(InputStream inputStream)
throws XmlMappingException, IOException {
// Implement stream-based unmarshalling
// ... unmarshal from input stream
return new MyCustomClass();
}
@Override
protected Object unmarshalReader(Reader reader)
throws XmlMappingException, IOException {
// Implement reader-based unmarshalling
// ... unmarshal from reader
return new MyCustomClass();
}
}A TrAX Source implementation that uses a Marshaller to provide XML content for transformation operations.
public class MarshallingSource extends SAXSource {
/**
* Create 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);
/**
* Return the Marshaller used by this MarshallingSource.
*/
public Marshaller getMarshaller();
/**
* Return the object to be marshalled.
*/
public Object getContent();
// Note: setInputSource and setXMLReader throw UnsupportedOperationException
}import org.springframework.oxm.support.MarshallingSource;
import org.springframework.oxm.Marshaller;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
// Use MarshallingSource with XSLT transformation
Marshaller marshaller = // ... get marshaller
Customer customer = new Customer("John", "Doe");
// Create MarshallingSource
MarshallingSource source = new MarshallingSource(marshaller, customer);
// Transform using XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(
new StreamSource(new FileInputStream("transform.xsl"))
);
StringWriter result = new StringWriter();
transformer.transform(source, new StreamResult(result));
String transformedXml = result.toString();Utility class for working with SAX and Spring's Resource abstraction.
public abstract class SaxResourceUtils {
/**
* Create a SAX InputSource from the given resource.
* Sets the system identifier to the resource's URL, if available.
* @param resource the resource
* @return the input source created from the resource
* @throws IOException if an I/O exception occurs
*/
public static InputSource createInputSource(Resource resource) throws IOException;
// Note: getSystemId(Resource) is a private method and not part of the public API
}import org.springframework.oxm.support.SaxResourceUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ClassPathResource;
import org.xml.sax.InputSource;
import javax.xml.transform.sax.SAXSource;
// Create InputSource from Spring Resource
Resource xmlResource = new ClassPathResource("data.xml");
InputSource inputSource = SaxResourceUtils.createInputSource(xmlResource);
// Use with SAX-based processing
SAXSource saxSource = new SAXSource(inputSource);
// The system ID is automatically set for proper error reporting and entity resolution
// Note: System ID retrieval is handled internally by createInputSource()import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.oxm.support.MarshallingSource;
import org.springframework.oxm.support.SaxResourceUtils;
import org.springframework.core.io.ClassPathResource;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
public class IntegratedExample {
public void demonstrateIntegration() throws Exception {
// Custom marshaller extending AbstractMarshaller
CustomMarshaller marshaller = new CustomMarshaller();
// Object to marshal
MyCustomClass object = new MyCustomClass();
// Create MarshallingSource for transformation
MarshallingSource source = new MarshallingSource(marshaller, object);
// Load XSLT stylesheet using SaxResourceUtils
Resource xsltResource = new ClassPathResource("transform.xsl");
InputSource xsltInput = SaxResourceUtils.createInputSource(xsltResource);
// Transform the marshalled XML
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new SAXSource(xsltInput));
StringWriter result = new StringWriter();
transformer.transform(source, new StreamResult(result));
String transformedXml = result.toString();
System.out.println("Transformed XML: " + transformedXml);
}
}import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.support.MarshallingSource;
import org.springframework.oxm.Marshaller;
@Configuration
public class MarshallingConfig {
@Bean
public Marshaller customMarshaller() {
return new CustomMarshaller();
}
// Bean factory method for creating MarshallingSource
public MarshallingSource createMarshallingSource(Object content) {
return new MarshallingSource(customMarshaller(), content);
}
}import org.springframework.oxm.support.MarshallingSource;
import org.springframework.oxm.XmlMappingException;
import javax.xml.transform.TransformerException;
public void handleErrors() {
try {
Marshaller marshaller = // ... get marshaller
Object content = // ... get content
MarshallingSource source = new MarshallingSource(marshaller, content);
// Use the source...
} catch (IllegalArgumentException e) {
System.err.println("Invalid marshaller or content: " + e.getMessage());
} catch (UnsupportedOperationException e) {
System.err.println("Attempted unsupported operation on MarshallingSource: " + e.getMessage());
}
// Handle transformation errors
try {
// ... transformation code
} catch (TransformerException e) {
System.err.println("Transformation failed: " + e.getMessage());
Throwable cause = e.getCause();
if (cause instanceof XmlMappingException) {
System.err.println("Underlying marshalling error: " + cause.getMessage());
}
}
}import org.springframework.oxm.support.SaxResourceUtils;
import org.springframework.core.io.Resource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import java.io.IOException;
public class CustomEntityResolver implements EntityResolver {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws IOException {
// Custom entity resolution using Spring resources
if (systemId != null && systemId.startsWith("classpath:")) {
String resourcePath = systemId.substring("classpath:".length());
Resource resource = new ClassPathResource(resourcePath);
if (resource.exists()) {
return SaxResourceUtils.createInputSource(resource);
}
}
return null; // Use default resolution
}
}import org.springframework.oxm.support.AbstractMarshaller;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParserFactory;
public class OptimizedMarshaller extends AbstractMarshaller {
// Override factory creation methods for performance tuning
@Override
protected DocumentBuilderFactory createDocumentBuilderFactory()
throws ParserConfigurationException {
DocumentBuilderFactory factory = super.createDocumentBuilderFactory();
// Performance optimizations
factory.setNamespaceAware(true);
factory.setValidating(false);
// Security settings
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
return factory;
}
@Override
protected SAXParserFactory createSaxParserFactory()
throws ParserConfigurationException, SAXException {
SAXParserFactory factory = super.createSaxParserFactory();
// Performance and security settings
factory.setNamespaceAware(true);
factory.setValidating(false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
return factory;
}
// ... implement abstract methods
}import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.oxm.support.MarshallingSource;
import org.springframework.oxm.support.SaxResourceUtils;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ClassPathResource;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
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.xml.sax.EntityResolver;
import org.xml.sax.SAXException;
import java.io.*;Install with Tessl CLI
npx tessl i tessl/maven-org-springframework--spring-oxm