What is Jaxb2Marshaller in Spring Web Services and what does it do?
answer
- Marshaller + Unmarshaller, both interfaces
- wraps JAXBContext, expensive -> singleton bean
- contextPath vs classesToBeBound
- no @XmlRootElement -> wrap in JAXBElement
- org.springframework.oxm.jaxb
basics
~10 sJaxb2Marshaller is a Spring adapter around JAXB that converts Java objects to XML (marshal) and XML back to Java objects (unmarshal), so you work with typed objects instead of raw XML in SOAP messages.
solid answer
~40 sJaxb2Marshaller is Spring WS's implementation of both the Marshaller and Unmarshaller interfaces, backed by JAXB (Jakarta XML Binding). It maps annotated Java classes (@XmlRootElement, @XmlType) to and from XML: marshal() writes an object to XML, unmarshal() reads XML into an object. You configure it either with setContextPath("com.example.generated") pointing at a package of JAXB-generated classes containing an ObjectFactory/jaxb.index, or with setClassesToBeBound(...) listing bound classes. It is used on both the client (WebServiceTemplate's marshaller/unmarshaller) and server (marshalling endpoints via @PayloadRoot / MarshallingPayloadMethodProcessor). It centralises XML binding so endpoint and client code deal in POJOs, not DOM. It caches a JAXBContext, which is expensive to build, so it's meant to be a singleton bean.
code
java · 14 lines@Configuration
public class OxmConfig {
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// Package(s) of JAXB-generated classes (must contain ObjectFactory / jaxb.index)
marshaller.setContextPath("com.example.ws.generated");
// Optional: pretty-print + XSD validation
marshaller.setMarshallerProperties(
Map.of(jakarta.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true));
return marshaller; // singleton: JAXBContext is built once and cached
}
}go deeper
Know it converts objects <-> XML for SOAP and that you configure a context path or classes to bind.
Explain both interfaces, the JAXBContext caching/singleton point, and contextPath vs classesToBeBound.
Discuss @XmlRootElement/JAXBElement wrapping, schema validation, exception hierarchy, and use on both client and server.
Reason about jakarta vs javax migration, MTOM, performance of JAXBContext, and OXM abstraction letting you swap marshallers.
**The problem it solves.** SOAP web services exchange XML. Working with raw XML (DOM, SAX) in business code is tedious and error-prone. *Marshalling* is the general technique of converting an in-memory object graph to a serialized form (here, XML) and back. Spring WS abstracts this behind two interfaces in `org.springframework.oxm`: `Marshaller` (object -> XML, `marshal(Object, Result)`) and `Unmarshaller` (XML -> object, `unmarshal(Source)`). **What Jaxb2Marshaller is.** `org.springframework.oxm.jaxb.Jaxb2Marshaller` implements *both* interfaces using **JAXB** (Jakarta XML Binding, formerly `javax.xml.bind`, now `jakarta.xml.bind`). JAXB itself maps Java classes annotated with `@XmlRootElement`, `@XmlType`, `@XmlElement`, `@XmlAttribute` etc. to XML. Jaxb2Marshaller wraps a `JAXBContext` and exposes it through the Spring OXM interfaces so the rest of Spring WS can stay binding-technology-agnostic (you could swap in a CastorMarshaller, Jibx, etc. historically). **Configuration — two mutually-common styles:** - `setContextPath("com.example.ws.generated")` — a colon-separated list of packages. Each package must contain JAXB metadata: either an `ObjectFactory` class or a `jaxb.index` file listing the bound classes. This is the normal setup when you generate classes from a WSDL/XSD with the JAXB XJC tool. - `setClassesToBeBound(Order.class, Customer.class, ...)` — you enumerate the annotated classes explicitly. Handy for hand-written POJOs. - `setPackagesToScan("com.example.model")` — scans for `@XmlRootElement`/`@XmlType` classes. Only set one of these. You can also set `setMarshallerProperties(Map)` (e.g. `Marshaller.JAXB_FORMATTED_OUTPUT = true`) and a `setSchema(Resource)` to enable XSD validation during marshal/unmarshal. **How it's used.** - *Client side:* you inject it into `WebServiceTemplate` via `setMarshaller` and `setUnmarshaller` (often the same instance since Jaxb2Marshaller is both). Then `webServiceTemplate.marshalSendAndReceive(requestObject)` returns a response object. - *Server side:* Spring WS's `MarshallingPayloadMethodProcessor` uses it so an `@Endpoint` method can take a JAXB request object as its parameter and return a JAXB response object, with the framework marshalling around it. **Key gotchas / edge cases:** - **JAXBContext is expensive to build** and thread-safe once built. Jaxb2Marshaller builds it lazily and caches it, so define it as a **singleton bean** — do not create one per request. - **`@XmlRootElement` vs no root element.** If a class has no `@XmlRootElement` (common with XJC-generated types), you cannot marshal it directly; you must wrap it in a `JAXBElement<T>` (usually produced by the generated `ObjectFactory.createXxx(...)`), or the marshaller throws about a missing root element. - **`mtomEnabled` / `supportJaxbElementClass`** are extra flags for binary attachments and raw `JAXBElement` support. - **Validation** via `setSchema` throws `UnmarshallingFailureException`/`MarshallingFailureException` (Spring's unified `XmlMappingException` hierarchy) on schema violations. - On Jakarta EE 9+ / Spring 6 the API is `jakarta.xml.bind.*`; on older Spring it was `javax.xml.bind.*`. Getting the wrong JAXB runtime on the classpath is a classic 'no implementation of JAXB found' error. **When to use it.** Any time you build a SOAP client or a contract-first SOAP endpoint in Spring WS and want to work with typed objects rather than DOM/StAX. It is the default and recommended OXM marshaller today.
- Why should Jaxb2Marshaller be a singleton bean?Because it builds and caches a JAXBContext, which is expensive to construct but thread-safe once built. Recreating it per request wastes CPU and memory; sharing one instance is both correct and efficient.
- You try to marshal a JAXB-generated class and get an error about a missing root element. Why?The class lacks @XmlRootElement (common for XJC-generated complex types). Wrap it in a JAXBElement<T> — typically via the generated ObjectFactory.createXxx(...) — so the marshaller knows the root element name and namespace.
saying these in an interview costs you the question
- Thinking Jaxb2Marshaller only marshals (it also unmarshals — it implements both interfaces)
- Creating a new Jaxb2Marshaller/JAXBContext per request
- Believing every JAXB class is directly marshallable without @XmlRootElement or a JAXBElement wrapper
- Confusing setContextPath (package names) with setClassesToBeBound (class objects) and setting both