In Spring Web Services, what is a contract-first SOAP endpoint and what does the @Endpoint annotation do?
answer
- XSD first, WSDL generated, Java last
- @Endpoint = @Controller for SOAP
- language-neutral contract is the real API
- MessageDispatcherServlet routes by payload root
- Spring-WS is contract-first by design
basics
~10 sContract-first means you write the XML schema (XSD/WSDL) first, then code against it. @Endpoint marks a class as a Spring-WS handler for SOAP requests — like @Controller but for SOAP instead of REST.
solid answer
~40 sSpring Web Services is built around contract-first development: you define the message contract (an XSD from which the WSDL is generated) before writing Java. A class annotated with @Endpoint is the Spring-WS equivalent of an MVC @Controller — it's a bean whose methods handle incoming SOAP messages. Each handler method is mapped to a specific request element via @PayloadRoot, receives the deserialized request XML through a @RequestPayload parameter, and returns an object marshalled back to XML as the @ResponsePayload. The framework (via a MessageDispatcherServlet and endpoint mappings) routes the SOAP body's root element to the matching method. Contract-first is the recommended and default style in Spring-WS — there is deliberately no strong 'start from Java' path — because the XML contract is the stable, language-neutral interface between systems.
code
java · 19 linesimport org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
@Endpoint
public class CountryEndpoint {
private static final String NS = "http://example.com/countries";
// GetCountryRequest / GetCountryResponse are generated from the XSD (xjc)
@PayloadRoot(namespace = NS, localPart = "GetCountryRequest")
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
GetCountryResponse response = new GetCountryResponse();
response.setCountry(lookup(request.getName()));
return response;
}
}go deeper
Know contract-first = XSD first, and @Endpoint is the SOAP handler class stereotype.
Explain the four annotations and the request flow through MessageDispatcherServlet.
Articulate why contract-first is the default and how the XSD drives code generation.
Frame contract stability and interoperability tradeoffs; when SOAP contract-first is justified vs REST.
## What is Spring Web Services (Spring-WS)? Spring-WS is a separate Spring project for building **SOAP** web services (not to be confused with Spring MVC for REST/HTTP). SOAP is an XML-based messaging protocol: requests and responses are XML documents wrapped in a SOAP envelope, usually over HTTP. ## Contract-first vs contract-last - **Contract-last (code-first):** you write Java classes, and a tool generates the XSD/WSDL from them. Easy to start, but the XML contract becomes a fragile by-product of your Java code — refactoring Java silently changes the contract your clients depend on. - **Contract-first:** you author the **XSD** (XML Schema Definition) by hand first. This XSD defines the shape of request and response messages. The **WSDL** (the service description) is generated from that XSD. Only then do you write Java to implement it. Spring-WS was designed almost exclusively around contract-first. The rationale: the XML contract is the real, language-neutral API boundary between systems, so it should be designed deliberately and kept stable, not derived from whatever your Java happens to look like today. ## Key annotations - **`@Endpoint`** — a class-level stereotype (like `@Controller`) that registers the bean as a SOAP message handler. Spring-WS scans for these. - **`@PayloadRoot(namespace = "...", localPart = "...")`** — method-level; maps a handler method to the qualified name (namespace + local element name) of the **root element of the SOAP body payload**. - **`@RequestPayload`** — parameter-level; tells Spring-WS to deserialize (unmarshal) the incoming XML payload into that method parameter (commonly a JAXB-generated object). - **`@ResponsePayload`** — method-level; tells Spring-WS to serialize (marshal) the returned object back into the SOAP response body. ## How a request flows 1. A `MessageDispatcherServlet` receives the SOAP request. 2. An **endpoint mapping** (typically `PayloadRootAnnotationMethodEndpointMapping`) inspects the qualified name of the payload's root element. 3. It finds the `@Endpoint` method whose `@PayloadRoot` matches and invokes it. 4. The `@RequestPayload` parameter is unmarshalled from XML; the returned `@ResponsePayload` is marshalled back. ## The XSD-driven part Because you start from the XSD, you typically use a build plugin (e.g. JAXB's `xjc` via the maven/gradle jaxb plugin) to generate Java request/response classes from the schema. Those generated classes are what your `@RequestPayload`/`@ResponsePayload` types are. Change the schema, regenerate — the contract drives the code, not the reverse. ## When to use Use contract-first SOAP when you must interoperate with existing WSDL/XSD contracts (enterprise integration, legacy systems, standards like ebXML/HL7), when the message contract must be stable and language-neutral across many clients, or when strong XML schema validation is a requirement. For greenfield internal APIs, REST/JSON is usually simpler.
- Why does Spring-WS favor contract-first over generating the WSDL from Java?The XML contract is the stable, language-neutral interface many clients depend on. Deriving it from Java makes it a fragile by-product — Java refactors leak into the contract. Authoring the XSD first keeps the contract intentional and stable.
- Is @Endpoint the same as @Controller?Conceptually yes — both are stereotypes that register request-handling beans. But @Endpoint handlers process SOAP payloads (mapped by XML element QName via @PayloadRoot), not HTTP paths, and are dispatched by MessageDispatcherServlet, not DispatcherServlet.
saying these in an interview costs you the question
- Thinking @Endpoint is for REST/HTTP endpoints
- Believing Spring-WS starts from Java and generates the XSD (that's contract-last)
- Confusing SOAP endpoints with @RestController / @RequestMapping