Reputation: 855
I need to use some XSDs files from an industry standard to generate a SOAP webservice from it. REST is not possible because the consumer is only able to do SOAP calls.
The parameters in the XSD are defined as the following:
<xsd:element name="getData">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Request" type="CT_getDataRequest" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="getDataResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Response" type="CT_getDataResponse" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
That is my endpoint definition:
@Endpoint
@RequiredArgsConstructor
public class DataEndpoint {
private static final String NAMESPACE_URI = "http://www.machine-config.net/namespace/data";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getData")
@ResponsePayload
public GetDataResponse getData(@RequestPayload GetData request) {
}
}
Here is my WsConfiguration:
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
messageDispatcherServlet.setApplicationContext(applicationContext);
messageDispatcherServlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(messageDispatcherServlet, "/ws/*");
}
@Bean(name = "dataDefinition")
public DefaultWsdl11Definition dataWsdl11Definition() {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("dataServicePortType");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.machine-config.net/namespace");
wsdl11Definition.setSchemaCollection(dataSchemas());
return wsdl11Definition;
}
@Bean(name = "dataSchema")
public XsdSchemaCollection dataSchemas() {
CommonsXsdSchemaCollection xsds = new CommonsXsdSchemaCollection(new ClassPathResource("xsd/data-2.18.1433.2.xsd"));
xsds.setUriResolver(new DefaultURIResolver());
xsds.setInline(true);
return xsds;
}
}
But inside the generated WSDL the following operation is generated:
<wsdl:operation name="getData">
<wsdl:output message="sch0:getDataResponse" name="getDataResponse"> </wsdl:output>
</wsdl:operation>
The wsdl:input
part is missing.
When I change the xsd:element getData
to getDataRequest
the wsdl:input
element is generated.
But that workaround will not work because the XSD will be delivered by a vendor and I am not allowed to change anything in this file.
How can I make spring-ws to recognize the input parameter without the Request Suffix?
Upvotes: 0
Views: 421
Reputation: 826
to have "request" parameters without the suffix expected by Spring, you need to:
private static class CustomMessagesProvider extends SuffixBasedMessagesProvider {
private static final String[] REQUEST_ELEMENTS = new String[]{
"getData", "paramaterWithoutRequeeeeest", "anotherInput"
};
@Override
protected boolean isMessageElement(Element element) {
if (super.isMessageElement(element)) {
return true;
} else {
boolean isElement = "element".equals(element.getLocalName()) &&
"http://www.w3.org/2001/XMLSchema".equals(element.getNamespaceURI());
String elementName = getElementName(element);
return isElement && Arrays.asList(REQUEST_ELEMENTS).contains(elementName);
}
}
}
private static class CustomPortTypesProvider extends SuffixBasedPortTypesProvider {
@Override
protected String getOperationName(Message message) {
String messageName = message.getQName().getLocalPart();
if (isInputMessage(message)) {
return messageName;
} else if (isOutputMessage(message)) {
return messageName.substring(0, messageName.length() - getResponseSuffix().length());
} else if (isFaultMessage(message)) {
return messageName.substring(0, messageName.length() - getFaultSuffix().length());
}
return null;
}
@Override
protected boolean isInputMessage(Message message) {
String messageName = message.getQName().getLocalPart();
return messageName.endsWith(getResponseSuffix()) && !messageName.endsWith(getFaultSuffix());
}
}
then, in your
@Bean(".....")
public ProviderBaseWsdl4jDefinition methodName(....) {
var wsdl4jDef = new Provider....
..
..
wsdl4jDef.setMessagesProvider(new CustomMEssagesProvider()); //<-- relevant code
}
Probably anyone who has/had to give support to legacy/old SOAP projects these days struggle with the same :)
Upvotes: 0