skip to content

What do @RequestPayload and @ResponsePayload do, and how do request/response objects get converted to and from XML?

level: middleimportance: should knowfreq 38%

answer

  1. @RequestPayload = unmarshal XML→object
  2. @ResponsePayload = marshal object→XML
  3. Jaxb2Marshaller wraps JAXB (OXM)
  4. classes generated by xjc from XSD
  5. MarshallingPayloadMethodProcessor bridges it

basics

~10 s

@RequestPayload unmarshals the incoming SOAP body XML into a Java object parameter; @ResponsePayload marshals the returned Java object back into the SOAP body XML. The conversion is done by a configured marshaller, typically JAXB.

solid answer

~40 s

@RequestPayload is a parameter annotation telling Spring-WS to deserialize (unmarshal) the SOAP body payload into that method argument. @ResponsePayload is a method annotation telling Spring-WS to serialize (marshal) the method's return value into the SOAP response body. The actual XML↔object conversion is delegated to a Marshaller/Unmarshaller — most commonly Spring's Jaxb2Marshaller wrapping JAXB, configured with the packages/classes generated from your XSD. Spring-WS's MarshallingPayloadMethodProcessor bridges the endpoint method and the marshaller. Because you're contract-first, the request/response classes usually come from xjc-generated JAXB bindings of the schema, carrying @XmlRootElement/@XmlType annotations that define exactly how they map to XML. If a method has no @ResponsePayload (e.g. a void operation or one that writes directly to the response), nothing is marshalled back.

code

java · 27 lines
java
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@EnableWs
@Configuration
public class WsConfig {

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller m = new Jaxb2Marshaller();
        // package(s) of xjc-generated classes bound to the XSD
        m.setContextPath("com.example.gen");
        return m;
    }
}

@Endpoint
class CountryEndpoint {
    @PayloadRoot(namespace = "http://example.com/countries",
                 localPart = "GetCountryRequest")
    @ResponsePayload                                   // return -> XML body
    public GetCountryResponse get(@RequestPayload GetCountryRequest req) { // XML body -> arg
        // ...
    }
}

go deeper

for a junior

Know one unmarshals the request, the other marshals the response.

for a middle

Name Jaxb2Marshaller/JAXB and that classes are xjc-generated from the XSD.

for a senior

Explain the OXM abstraction, MarshallingPayloadMethodProcessor, and JAXBElement/root-element nuances.

for a principal

Weigh marshaller choices, schema-to-code generation in the build, and drift risks.

## Marshalling and unmarshalling - **Unmarshalling** = XML → Java object (deserialize the request). - **Marshalling** = Java object → XML (serialize the response). Spring-WS uses Spring's Object/XML Mapping (OXM) abstraction: interfaces `org.springframework.oxm.Marshaller` and `Unmarshaller`. The default and most common implementation is **`Jaxb2Marshaller`**, which delegates to **JAXB** (Jakarta XML Binding). Other options exist (Castor, XStream, JiBX historically) but JAXB is standard. ## The annotations - **`@RequestPayload`** (parameter-level): marks which method argument should receive the unmarshalled request payload. Spring-WS takes the SOAP body's payload, runs it through the `Unmarshaller`, and passes the resulting object. - **`@ResponsePayload`** (method-level): marks that the method's return value should be marshalled into the SOAP response body. Behind the scenes, **`MarshallingPayloadMethodProcessor`** resolves the `@RequestPayload` argument and handles the `@ResponsePayload` return value, using the configured marshaller/unmarshaller. ## Where the classes come from (XSD-driven) In contract-first, you don't hand-write the request/response classes. You run a JAXB binding compiler (**`xjc`**, via a Maven/Gradle JAXB plugin) against your XSD. It generates Java classes annotated with `@XmlRootElement`, `@XmlType`, `@XmlElement`, etc. These annotations tell JAXB precisely how each field maps to an XML element/attribute — so the marshalling matches your schema exactly. Regenerate when the schema changes. ## Configuration A typical config registers the marshaller with the package(s) of generated classes: ```java @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller m = new Jaxb2Marshaller(); m.setContextPath("com.example.generated"); // or setPackagesToScan / setClassesToBeBound return m; } ``` Spring-WS's `@EnableWs` / `WsConfigurerAdapter` wiring picks up the marshaller for the marshalling method processor. ## Gotchas - **`@XmlRootElement` requirement:** the unmarshalled request type usually needs to be a JAXB root element (or wrapped via `JAXBElement`). xjc generates these based on top-level XSD `element` declarations; if the schema only declares types, you may get `JAXBElement<T>` wrappers or need an `ObjectFactory`. - **Namespace consistency:** the JAXB `@XmlRootElement` namespace must line up with the `@PayloadRoot` namespace — both come from the XSD, so keep them in sync by generating from one schema. - **Missing `@ResponsePayload`:** then the return value isn't marshalled — useful for one-way (void) operations, but a bug if you expected a response body. - **Not just JAXB:** any OXM `Marshaller` works, but mixing hand-written classes with contract-first schema drift is a maintenance hazard. ## When to use This pairing is the standard way to implement any contract-first SOAP operation: declare the operation with `@PayloadRoot`, take the request via `@RequestPayload`, return the response via `@ResponsePayload`, and let JAXB handle the XML.

  • Which Spring/Java technology actually converts the XML to and from objects?
    Spring's OXM Marshaller/Unmarshaller abstraction, most commonly Jaxb2Marshaller delegating to JAXB. Spring-WS's MarshallingPayloadMethodProcessor invokes it for @RequestPayload/@ResponsePayload.
  • Where do the request/response Java classes come from in contract-first?
    They're generated from the XSD by the JAXB binding compiler (xjc), typically via a Maven/Gradle plugin. They carry @XmlRootElement/@XmlType annotations so JAXB maps them to XML exactly per the schema.

saying these in an interview costs you the question

  • Saying Spring-WS uses Jackson/JSON for the payload (it's XML via JAXB)
  • Hand-writing request classes instead of generating from the XSD in a contract-first flow
  • Thinking @RequestPayload works like @RequestBody with content negotiation
  • Forgetting @ResponsePayload and expecting a response body anyway

context