skip to content

WSDL Generation

A WSDL definition is generated dynamically from your XSD and served by the message dispatcher servlet. Practical detail for anyone who has to hand an interface description to another team.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

4

How do you wire MessageDispatcherServlet with ServletRegistrationBean in a Spring Boot app, and why can't you reuse the default DispatcherServlet?

level: middleimportance: must knowfreq 55%

answer

  1. MessageDispatcherServlet = SOAP front controller
  2. ServletRegistrationBean maps it to /ws/*
  3. setApplicationContext(ctx) to reuse Boot context
  4. setTransformWsdlLocations(true) rewrites soap:address
  5. payload-root dispatch, not URL/verb

basics

~10 s

Register MessageDispatcherServlet as a separate servlet via a ServletRegistrationBean mapped to something like /ws/*. It's Spring-WS's own front controller for SOAP; the regular DispatcherServlet handles MVC/REST, not SOAP message dispatching or WSDL serving.

solid answer

~40 s

Spring-WS ships its own front controller, MessageDispatcherServlet, which knows how to route incoming SOAP messages to @Endpoint beans and how to serve generated WSDLs. In Spring Boot you expose it with a ServletRegistrationBean: construct MessageDispatcherServlet, call setApplicationContext(context) so it shares the Boot context, enable setTransformWsdlLocations(true) so advertised location URIs get rewritten to the caller's host, and register it at a URL mapping like /ws/*. That mapping is the SOAP boundary — every request under it goes through message dispatching. You keep it separate from the auto-configured DispatcherServlet (which owns /) because DispatcherServlet does HTTP-verb/handler-based MVC dispatch, whereas MessageDispatcherServlet does SOAP-payload-based dispatch (PayloadRootAnnotationMethodEndpointMapping etc.) and hosts the WsdlDefinition beans. Two servlets, two mappings, one ApplicationContext.

code

java · 13 lines
java
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {

    @Bean
    public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(
            ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext); // reuse Boot context
        servlet.setTransformWsdlLocations(true);            // rewrite soap:address
        return new ServletRegistrationBean<>(servlet, "/ws/*");
    }
}

go deeper

for a junior

Know MessageDispatcherServlet is registered via ServletRegistrationBean at a path like /ws/*.

for a middle

Explain setApplicationContext and setTransformWsdlLocations and why a second servlet is needed.

for a senior

Contrast payload-root dispatch vs MVC handler dispatch and discuss the child-context pitfall.

for a principal

Address security boundaries for /ws/*, proxy/location rewriting strategy, and coexistence with MVC in one context.

## Two different front controllers Spring MVC's front controller is **`DispatcherServlet`** — it dispatches HTTP requests to `@Controller`/`@RestController` handlers based on URL + HTTP method. SOAP is different: the *operation* is identified by the **payload** (the root element of the SOAP body), not by URL/verb. So Spring-WS provides **`org.springframework.ws.transport.http.MessageDispatcherServlet`**, a subclass that performs **message dispatching**: it consults endpoint mappings like `PayloadRootAnnotationMethodEndpointMapping` (match by request payload root element) or `SoapActionAnnotationMethodEndpointMapping` to find the right `@Endpoint` method. It *also* knows how to locate `WsdlDefinition` beans (your `DefaultWsdl11Definition`) and serve them as `/{beanName}.wsdl`. You cannot reuse the default `DispatcherServlet` for this: it has no concept of payload-root dispatch and does not serve `WsdlDefinition` beans. They coexist — MVC on `/`, SOAP on `/ws/*`. ## Wiring with ServletRegistrationBean In a Spring Boot app you register an extra servlet by declaring a `ServletRegistrationBean<MessageDispatcherServlet>`: ```java @Bean public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext ctx) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(ctx); servlet.setTransformWsdlLocations(true); return new ServletRegistrationBean<>(servlet, "/ws/*"); } ``` Key points: - **`setApplicationContext(ctx)`** — critical. `MessageDispatcherServlet` normally creates its *own* child WebApplicationContext from an XML/config file. In Boot you want it to reuse the existing Boot context (where your `@Endpoint`, `XsdSchema`, and `DefaultWsdl11Definition` beans live), so you inject the current `ApplicationContext` and set it explicitly. Forgetting this leads to it not finding your endpoints/WSDL beans. - **URL mapping `/ws/*`** — the second constructor arg. This is the SOAP boundary. `/ws/countries.wsdl` (GET) returns the WSDL; POSTs of SOAP messages under `/ws/*` are dispatched to endpoints. - **`setTransformWsdlLocations(true)`** — rewrites the `soap:address location` in the generated WSDL to match the host/port/context the client used, instead of the static `locationUri`. Essential behind proxies/load balancers or when the app doesn't know its public URL. - **`@EnableWs`** — put on a `@Configuration` class (often extending `WsConfigurerAdapter`); it imports the Spring-WS infrastructure (endpoint mappings, adapters, marshalling support). ## Gotchas - **Mapping overlap**: don't map the SOAP servlet to `/` — it would shadow MVC. Give it a dedicated prefix. - **Load order / bean name**: the WSDL URL path segment is the `DefaultWsdl11Definition` *bean name*, resolved relative to the servlet mapping. Bean `countries` at `/ws/*` -> `/ws/countries.wsdl`. - **Child-context surprise**: if you forget `setApplicationContext`, `MessageDispatcherServlet` looks for a `*-servlet.xml` and fails to see Boot beans. - **Security**: the `/ws/*` path is separate from your MVC security; configure Spring Security matchers for it explicitly. ## When to use Any Spring Boot SOAP service. Boot has no starter that auto-registers `MessageDispatcherServlet` for you beyond `spring-boot-starter-web-services` bringing the dependency; you still supply this `@Bean`.

  • Why must you call setApplicationContext on the MessageDispatcherServlet in Spring Boot?
    By default it spins up its own child WebApplicationContext from an XML config and wouldn't see your Boot-managed @Endpoint/XsdSchema/DefaultWsdl11Definition beans. Injecting the current ApplicationContext makes it reuse them.
  • What does setTransformWsdlLocations(true) do?
    It rewrites the soap:address location URI in the generated WSDL to reflect the actual request host/port/context path, so clients behind proxies get a reachable endpoint instead of the static locationUri.
  • How does MessageDispatcherServlet decide which endpoint handles a request?
    By the SOAP payload root element (PayloadRootAnnotationMethodEndpointMapping) or SOAPAction, not by URL/HTTP verb like DispatcherServlet.

saying these in an interview costs you the question

  • Claiming the regular DispatcherServlet can serve WSDL/SOAP
  • Mapping the SOAP servlet to '/' and shadowing MVC
  • Omitting setApplicationContext so endpoints aren't found
  • Thinking SOAP operations are chosen by URL path/HTTP method

context

open as a page

What is dynamic WSDL generation in Spring Web Services, and how does DefaultWsdl11Definition produce it?

level: juniorimportance: should knowfreq 45%

basics

~10 s

Spring-WS generates the WSDL at runtime from your XSD schema instead of you hand-writing it. You declare a DefaultWsdl11Definition bean pointing at an XsdSchema, and Spring builds the WSDL from that schema on request.

open as a page

How does DefaultWsdl11Definition decide which schema elements become WSDL operations, and how do requestSuffix/responseSuffix and multiple schemas factor in?

level: seniorimportance: should knowfreq 35%

basics

~20 s

It scans top-level XSD element declarations and pairs those ending in the request suffix ('Request' by default) with matching 'Response' ones, turning each pair into a WSDL operation. You can change the suffixes; multiple schemas need a schema collection.

open as a page

A client fetches the generated WSDL through a load balancer and the soap:address points to an internal host. How does Spring-WS solve this, and what are the tradeoffs of location transformation?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

Enable setTransformWsdlLocations(true) on MessageDispatcherServlet. Spring-WS then rewrites the soap:address location in the served WSDL to match the host, port, and path the client actually used, so proxied clients get a reachable endpoint instead of the static locationUri.

open as a page