You need something that combines a URI and PayloadRoot . Unfortunately, Spring-Ws has nothing of the kind. But since it is very extensible, it is really easy to achieve.
TL DR
See This thread on GitHub for a working example.
More details
You need to create a combined URI + QName mapping to instances of org.springframework.ws.server.endpoint.MethodEndpoint . You should also minimize code that duplicates existing Spring -Ws functions.
So 1) You need to explicitly configure Spring -Ws annotations without using <sws:annotation-driven /> :
This is your requirement (with my schemes):
<ws:dynamic-wsdl id="spml-readonly" portTypeName="SpmlReadOnlyService" locationUri="SpmlReadOnly"> <ws:xsd location="classpath:springws/model/schema.xsd" /> </ws:dynamic-wsdl> <ws:dynamic-wsdl id="spml-crud" portTypeName="SpmlCrudService" locationUri="SpmlCrud"> <ws:xsd location="classpath:springws/model/schema.xsd" /> <ws:xsd location="classpath:springws/model/schema2.xsd" /> </ws:dynamic-wsdl>
This is all you need to do manually, which is usually set up by <sws:annotation-driven /> (one adapter with one JAXB marshaller):
<bean class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter"> <property name="methodArgumentResolvers"> <list> <ref local="marshallingPayloadMethodProcessor"/> </list> </property> <property name="methodReturnValueHandlers"> <list> <ref local="marshallingPayloadMethodProcessor"/> </list> </property> </bean> <bean id="marshallingPayloadMethodProcessor" class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor"> <property name="marshaller" ref="marshaller" /> <property name="unmarshaller" ref="marshaller" /> </bean> <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> <property name="contextPaths"> <list> <value>springws.model</value> </list> </property> </bean>
This is a custom display:
<bean class="springws.PathAndPayloadRootAnnotationEndpointMapping" />
And 2) you must create your own mapping
public class PathAndPayloadRootAnnotationEndpointMapping extends PayloadRootAnnotationMethodEndpointMapping { @Override protected QName getLookupKeyForMessage(MessageContext messageContext) throws Exception { String urlPart = ""; QName payloadRootPart = super.getLookupKeyForMessage(messageContext); TransportContext transportContext = TransportContextHolder.getTransportContext(); if (transportContext != null) { WebServiceConnection connection = transportContext.getConnection(); if (connection != null && connection instanceof HttpServletConnection) { String requestURI = ((HttpServletConnection)connection).getHttpServletRequest().getRequestURI(); String contextPath = ((HttpServletConnection)connection).getHttpServletRequest().getContextPath(); urlPart = requestURI.substring(contextPath.length()); } } return new QName(payloadRootPart.getNamespaceURI(), urlPart + "/" + payloadRootPart.getLocalPart()); } @Override protected List<QName> getLookupKeysForMethod(Method method) { List<QName> result = new ArrayList<QName>(); RequestMapping rm = AnnotationUtils.findAnnotation(method.getDeclaringClass(), RequestMapping.class); String urlPart = rm == null || rm.value().length != 1 ? "" : rm.value()[0]; List<QName> methodPart = super.getLookupKeysForMethod(method); for (QName qName : methodPart) { result.add(new QName(qName.getNamespaceURI(), urlPart + "/" + qName.getLocalPart())); } return result; } }
which continues org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping . And all he does is expand the keys (QNames of the root elements of the payload) of messages with information extracted from the URI of the endpoint. I used the Spring @org.springframework.web.bind.annotation.RequestMapping annotation for this, but someone, thinking that this is a hack, can create their own annotation.
So for the endpoint:
@org.springframework.ws.server.endpoint.annotation.Endpoint @RequestMapping("/ws/SpmlReadOnly") public class Endpoint1 { @ResponsePayload @PayloadRoot(namespace = "urn:test", localPart = "method1Request") public Response2 method(@RequestPayload Request1 request) throws Exception { return new Response2("e1 m1"); } }
key missing:
namespace = urn:test localName = method1Request
but this:
namespace = urn:test localName = /ws/SpmlReadOnly/method1Request
The protected QName getLookupKeyForMessage(MessageContext messageContext) ensures that the display URI does not depend on the context of the WAR application is deployed to.