From spring
Build contract-first SOAP services and clients in Spring with XSD or WSDL contracts, `@Endpoint` handlers, XML marshalling, `WebServiceTemplate`, and WS-Security integration. Use this skill when building contract-first SOAP services or clients in Spring with XSD or WSDL contracts, `@Endpoint` handlers, XML marshalling, `WebServiceTemplate`, SOAP faults, and WS-Security-aware integration.
npx claudepluginhub ririnto/sinon --plugin springThis skill uses the workspace's default tool permissions.
Use this skill when building contract-first SOAP services or clients in Spring with XSD or WSDL contracts, `@Endpoint` handlers, XML marshalling, `WebServiceTemplate`, SOAP faults, and WS-Security-aware integration.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Use this skill when building contract-first SOAP services or clients in Spring with XSD or WSDL contracts, @Endpoint handlers, XML marshalling, WebServiceTemplate, SOAP faults, and WS-Security-aware integration.
Use spring-web-services for SOAP transport, XML contract publication, endpoint mapping, SOAP client calls, and SOAP-specific testing.
The ordinary Spring Web Services job is:
MessageDispatcherServlet registration only when the deployment needs custom servlet mapping.@Endpoint handler that maps one payload root to one application use case.In Spring Boot, prefer the starter-managed ordinary path first: keep the starter, marshaller, schema, endpoint, and test wiring explicit, but do not reintroduce manual servlet setup unless the deployment actually needs custom servlet registration.
SKILL.md for the ordinary endpoint-plus-template path: contract-first XSD and WSDL publication, servlet registration, @Endpoint handlers, JAXB marshalling, WebServiceTemplate, basic SOAP fault mapping, and contract tests.Use the Boot starter for ordinary SOAP server or client work and add test support for SOAP contract verification.
For the current Boot 4.x line, use spring-boot-starter-webservices. Older Boot lines may still use spring-boot-starter-web-services.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webservices</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
@Bean
XsdSchema holidaysSchema() {
return new SimpleXsdSchema(new ClassPathResource("xsd/holidays.xsd"));
}
@Bean
Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.example.hr.schema");
return marshaller;
}
spring.webservices.path=/ws
spring.webservices.wsdl-locations=classpath:/wsdl
@Bean
ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(context);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
Use the Boot property path above as the ordinary path first. Add explicit servlet registration only when the application is not relying on Spring Boot's auto-configured SOAP servlet path or when the mapping must differ from the default deployment shape.
@Bean(name = "holidays")
DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema holidaysSchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setPortTypeName("HolidaysPort");
definition.setLocationUri("/ws");
definition.setTargetNamespace("http://example.com/hr");
definition.setSchema(holidaysSchema);
return definition;
}
WebServiceTemplateBuilder client shape@Bean
WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder, Jaxb2Marshaller marshaller) {
return builder.setMarshaller(marshaller).setUnmarshaller(marshaller).build();
}
@Bean
SoapFaultMappingExceptionResolver soapFaultMappingExceptionResolver() {
SoapFaultMappingExceptionResolver resolver = new SoapFaultMappingExceptionResolver();
Properties exceptionMappings = new Properties();
exceptionMappings.setProperty(BookingNotAllowedException.class.getName(), SoapFaultDefinition.SERVER + ",Booking failed");
SoapFaultDefinition definition = new SoapFaultDefinition();
definition.setFaultCode(SoapFaultDefinition.SERVER);
resolver.setExceptionMappings(exceptionMappings);
resolver.setDefaultFault(definition);
resolver.setOrder(1);
return resolver;
}
@PayloadRoot handler small and map XML objects into application commands or queries immediately.@Endpoint
class HolidayEndpoint {
private static final String NAMESPACE = "http://example.com/hr";
private final HolidayService service;
HolidayEndpoint(HolidayService service) {
this.service = service;
}
@PayloadRoot(namespace = NAMESPACE, localPart = "HolidayRequest")
@ResponsePayload
HolidayResponse handle(@RequestPayload HolidayRequest request) {
return service.book(request);
}
}
@Configuration
@EnableWs
class WsConfig extends WsConfigurerAdapter {
@Bean
ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(context);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "holidays")
DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema holidaysSchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setPortTypeName("HolidaysPort");
definition.setLocationUri("/ws");
definition.setTargetNamespace("http://example.com/hr");
definition.setSchema(holidaysSchema);
return definition;
}
}
WebServiceTemplate client call@Service
class HolidayClient {
private final WebServiceTemplate webServiceTemplate;
HolidayClient(WebServiceTemplate webServiceTemplate) {
this.webServiceTemplate = webServiceTemplate;
}
HolidayResponse book(HolidayRequest request) {
return (HolidayResponse) webServiceTemplate.marshalSendAndReceive(request);
}
}
MockWebServiceClient@SpringBootTest
class HolidayEndpointTests {
@Autowired
ApplicationContext applicationContext;
@Test
void respondsWithContractPayload() throws Exception {
MockWebServiceClient client = MockWebServiceClient.createClient(applicationContext);
client.sendRequest(withPayload(new StringSource("<HolidayRequest xmlns='http://example.com/hr'/>")))
.andExpect(noFault())
.andExpect(payload(new StringSource("<HolidayResponse xmlns='http://example.com/hr'><status>OK</status></HolidayResponse>")));
}
}
MockWebServiceServer@SpringBootTest
class HolidayClientTests {
@Autowired
HolidayClient client;
@Autowired
WebServiceTemplate template;
@Test
void sendsRequest() {
MockWebServiceServer server = MockWebServiceServer.createServer(template);
server.expect(payload(new StringSource("<HolidayRequest xmlns='http://example.com/hr'/>")))
.andRespond(withPayload(new StringSource("<HolidayResponse xmlns='http://example.com/hr'><status>OK</status></HolidayResponse>")));
client.book(new HolidayRequest());
server.verify();
}
}
/ws
@PayloadRoot(namespace = "http://example.com/hr", localPart = "HolidayRequest")
<HolidayResponse xmlns="http://example.com/hr">
<status>OK</status>
</HolidayResponse>
WebServiceTemplate.