Reputation: 21
I am developing a SOAP service based on Spring WebServices
, which, according to a business task, must proxy a SOAP
request through itself.
My problem is that I can't get a correctly generated WSDL at the output, which I could give to the customer, since in fact there is almost no description of elements in my main xsd due to the fact that I use a generated SOAP service, objects from which participate in @RequestPayload and @ResponsePayload. The only elements added by my service are setDataInQueue
and message
(currently not used, but will be needed later).
Due to the large number of links in the xsd file, I could not publish my question, as it was marked as spam, so I had to omit them.
Generated WSDL on localhost:8080/ws/proxy.wsdl
:
<wsdl:definitions ...>
<wsdl:types>
<xs:schema ...>
<xs:import schemaLocation="message.xsd"/>
<xs:import namespace="http://service.example.com/" schemaLocation="setDataInQueue.xsd"/>
</xs:schema>
</wsdl:types>
<wsdl:portType name="ProxyPort"></wsdl:portType>
<wsdl:binding name="ProxyPortSoap11" type="tns:ProxyPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
</wsdl:binding>
<wsdl:service name="ProxyService">
<wsdl:port binding="tns:ProxyPortSoap11" name="ProxyPortSoap11">
<soap:address location="http://localhost:8080/ws"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Generated WSDL on localhost:8080/ws/ehdproxy.wsdl
:
<wsdl:definitions ... >
<wsdl:types>
<xs:schema ...>
<xs:import schemaLocation="message.xsd"/>
<xs:import namespace="service.exampe.com/" schemaLocation="setDataInQueue.xsd"/>
</xs:schema>
</wsdl:types>
<wsdl:portType name="EhdProxyPort"></wsdl:portType>
<wsdl:binding name="EhdProxyPortSoap11" type="tns:EhdProxyPort">
<soap:binding style="document" transport="schemas.xmlsoap.org/soap/http"/>
</wsdl:binding>
<wsdl:service name="EhdProxyService">
<wsdl:port binding="tns:EhdProxyPortSoap11" name="EhdProxyPortSoap11">
<soap:address location="localhost:8080/ws"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
As you can see, the final wsdls do not have any sections with operations and descriptions of requests/responses, according to which the customer could eventually generate a client to work with my proxy service.
I have two endpoints: I had to split the endpoint into separate classes and declarations since they have a different namespace.
ProxyEndPoint
:
@Endpoint
@RequiredArgsConstructor
public class ProxyEndPoint {
public static final String BUS_NAMESPACE_URI = "http...service.example.com/";
private final ConverterService converterService;
private final EhdService ehdService;
@ResponsePayload
@PayloadRoot(namespace = BUS_NAMESPACE_URI, localPart = "setDataInQueue")
public SetDataInQueueResponse handleSetDataInQueue(@RequestPayload SetDataInQueue request) {
final var converted = this.converterService.convert(request);
return this.ehdService.callSetDataInQueue(converted);
}
EhdProxyEndPoint
:
@Endpoint
@RequiredArgsConstructor
public class EhdProxyEndPoint {
public static final String EHD_NAMESPACE_URI = "http...contractor.com/";
private final EhdService ehdService;
@ResponsePayload
@PayloadRoot(namespace = EHD_NAMESPACE_URI, localPart = "setDataInResult")
public SetDataInResultResponse handleSetDataInResult(@RequestPayload SetDataInResult request) {
return this.ehdService.callSetDataInResult(request);
}
}
These endpoints are configured according to one of the examples of the main guides from Spring WebServices:
WebServiceConfig
:
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(context);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "proxy")
public DefaultWsdl11Definition proxySchemaDefinition(XsdSchema proxySchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setServiceName("ProxyService");
definition.setPortTypeName("ProxyPort");
definition.setLocationUri("/ws");
definition.setTargetNamespace(ProxyEndPoint.BUS_NAMESPACE_URI);
definition.setSchema(proxySchema);
return definition;
}
@Bean(name = "ehdproxy")
public DefaultWsdl11Definition ehdProxySchemaDefinition(XsdSchema proxySchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setServiceName("EhdProxyService");
definition.setPortTypeName("EhdProxyPort");
definition.setLocationUri("/ws");
definition.setTargetNamespace(EhdProxyEndPoint.EHD_NAMESPACE_URI);
definition.setSchema(proxySchema);
return definition;
}
@Bean
public XsdSchema proxySchema() {
return new SimpleXsdSchema(new ClassPathResource("/xsd/proxy.xsd"));
}
}
resources/xsd/proxy.xsd
:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
...
jaxb:version="3.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
>
<xs:import schemaLocation="message.xsd"/>
<xs:import namespace="service.example.com" schemaLocation="setDataInQueue.xsd"/>
</xs:schema>
resources/xsd/setDataInQueue.xsd
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0"
...
>
<xs:element name="setDataInQueue" type="tns:setDataInQueue"/>
<xs:complexType name="setDataInQueue">
<xs:sequence>
<xs:element name="FileName" type="xs:string"/>
<xs:element name="File" type="xs:base64Binary"/>
<xs:element name="Signature" type="xs:base64Binary"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
/resources/xsd/message.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0">
<xs:element name="category" type="categoryEntity" />
<xs:element name="message" type="messageEntity" />
<xs:complexType name="messageEntity">
<xs:sequence>
<xs:element name="id" type="xs:string" minOccurs="0" />
<xs:element name="catalog" type="catalogEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="catalogEntity">
<xs:sequence>
<xs:element name="item" type="itemEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="parent_catalog_id" type="xs:int" />
</xs:complexType>
<xs:complexType name="itemEntity">
<xs:sequence>
<xs:element name="geodata" type="xs:string" minOccurs="0" />
<xs:element name="categories" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element ref="category" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="data" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="attribute" type="attributeEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="action" type="xs:string" />
<xs:attribute name="isManualGeo" type="xs:boolean" />
</xs:complexType>
<xs:complexType name="categoryEntity">
<xs:simpleContent>
<xs:extension base="xs:int">
<xs:attribute name="nameHier" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="attributeEntity">
<xs:sequence>
<xs:element name="values" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="value" type="valueEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="field_id" type="xs:int" />
<xs:attribute name="type" type="xs:string" />
<xs:attribute name="pk" type="xs:string" />
<xs:attribute name="isManual" type="xs:boolean" />
</xs:complexType>
<xs:complexType name="valueEntity">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="occurrence" type="xs:int" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
resources/jxb/bindings.xjb
(for generate @XMlRootElement
annotation):
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings version="3.0"
...
jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings generateElementProperty="false" >
<xjc:simple/>
<xjc:serializable uid="-1"/>
</jaxb:globalBindings>
</jaxb:bindings>
Since I need to proxy requests from another SOAP service, I use WSDL-based code generation using wsimport:
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.5'
id 'io.spring.dependency-management' version '1.1.3'
}
group = 'com.group'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '21'
}
ext.jaxwsSourceDir = "${buildDir}/generated/sources/jaxws"
configurations {
jaxb
jaxws
compileOnly {
extendsFrom annotationProcessor
}
}
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir 'build/generated/sources/jaxb'
srcDir jaxwsSourceDir
}
}
}
task genJaxb {
ext.sourcesDir = "${buildDir}/generated/sources/jaxb"
ext.schema = "src/main/resources/xsd/proxy.xsd"
ext.binding = "src/main/resources/jxb/bindings.xjb"
outputs.dir sourcesDir
doLast() {
project.ant {
taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
classpath: configurations.jaxb.asPath
mkdir(dir: sourcesDir)
xjc(destdir: sourcesDir, schema: schema, binding: ext.binding) {
arg(value: "-wsdl")
produces(dir: sourcesDir, includes: "**/*.java")
}
}
}
}
task wsimport {
System.setProperty('javax.xml.accessExternalSchema', 'all')
description = 'Generate classes from wsdl using wsimport'
doLast {
project.mkdir(jaxwsSourceDir)
ant {
taskdef(name: 'wsimport',
classname: 'com.sun.tools.ws.ant.WsImport',
classpath: configurations.jaxws.asPath
)
wsimport(
keep: true,
destdir: jaxwsSourceDir,
extension: "true",
verbose: true,
wsdl: "%WSDL LINK PLACEHOLDER%", // <- WSDL contractor inserted here
binding: "${projectDir}/src/main/resources/jxb/bindings.xjb",
xnocompile: true,
package: "contractor") {
xjcarg(value: "-XautoNameResolution")
}
}
}
}
compileJava.dependsOn genJaxb, wsimport
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web-services'
// support xml/xsd/wsdl
implementation 'wsdl4j:wsdl4j'
implementation 'com.sun.xml.ws:rt:4.0.2'
jaxb('org.glassfish.jaxb:jaxb-xjc:4.0.4')
jaxb('org.glassfish.jaxb:jaxb-core:4.0.4')
jaxb('org.glassfish.jaxb:jaxb-runtime:4.0.4')
jaxws 'com.sun.xml.ws:jaxws-tools:4.0.2',
'jakarta.xml.ws:jakarta.xml.ws-api:3.0.0',
'jakarta.xml.bind:jakarta.xml.bind-api:4.0.1',
'jakarta.activation:jakarta.activation-api:2.1.2',
'com.sun.xml.ws:jaxws-rt:4.0.2'
// dev / test utils ...
}
I have been developing a SOAP service quite recently and have studied a lot of guides when trying to solve the problem, but I have not been able to achieve results. I would also like to note that I get an error when trying to import my SOAP service into SoapUI:
Error loading [http://localhost:8080/ws/message.xsd]: org.apache.xmlbeans.XmlException: org.apache.xmlbeans.XmlException: error: Premature end of file
Upvotes: 1
Views: 148