So I am new to the whole SOAP and server concept. Ive put together a basic JAX-RPC and JAX-WS. I overall want to pass an .XML file to a web service, receive a response, and write it into a directory. Where do i start, what should I use, and where can find a tutorial/information based on it. Thank you!
Essentially there are two approaches you can take when designing a web service. The top down approach and the bottom up approach. I will give you a brief explanation of both methods and their ups and downs. There will also be links to some tutorials.
Top Down:
In the top down approach you start by modelling a XSD which will contain your request and response messages and the data structures that those requests and responses will use. You then model the operations i.e. the request and response that flows between client and service and finally you put this together into a WSDL. This resulting WSDL is then imported into a IDE such as Netbeans or Eclipse and you then start coding the internals of the service.
For example lets say you have a product service. In this service you want to create a operation that will search for a particular product based on product code. Thus you want to query the product service for product objects. The service will be called ProductService and the operation will be called GetProduct.
To achieve this you need to model a product object which has two string properties called description and code. You will also need to model a GetProductRequest message and a GetProductResponse message.
This might take on the following structures:
The code for the XSD would look like this:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns="http://www.wsexample.com/ProductService_V1/Product"
elementFormDefault="qualified"
targetNamespace="http://www.wsexample.com/ProductService_V1/Product"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="ProductCode_Type">
<xs:annotation>
<xs:documentation>This the product code type. It is based on the string data type it must be 8 characters long.
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="8" />
<xs:maxLength value="8" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ProductDescription_Type">
<xs:annotation>
<xs:documentation>This is the base class for the product description field. This is a text field up to 255 characters long.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:maxLength value="255" />
</xs:restriction>
</xs:simpleType>
<xs:complexType name="Product_Type">
<xs:annotation>
<xs:documentation>This is the product base class it is used to perform CRUD operations with on all of the product service operations.
</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="ProductCode"
type="ProductCode_Type"
minOccurs="1"
maxOccurs="1" />
<xs:element name="ProductDescription"
type="ProductDescription_Type"
minOccurs="0"
maxOccurs="1" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="GetProductRequest_Type">
<xs:annotation>
<xs:documentation>This is the base class for the Get Product Request message. In the message you must pass one and only one product code which to search for. </xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="Product"
type="Product_Type" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="GetProductResponse_Type">
<xs:annotation>
<xs:documentation>This is the get product response message and will contain the result of the results of calling the getproductdescription operation on the Product service.
It will contain a product code which was passed in the Get Product Request message and optionally return one description.</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="Product"
type="Product_Type" />
</xs:sequence>
</xs:complexType>
<xs:element name="GetProductRequest"
type="GetProductRequest_Type" />
<xs:element name="GetProductResponse"
type="GetProductResponse_Type" />
</xs:schema>
You will now need to create a new WSDL to describe the service and use this XSD(I called it product.xsd) in this WSDL. As you can see we have modelled data structures to transport the product object and we have modeled the operations used in the service.
Our WSDL might look like this then:
This is the code for the WSDL
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="ProductService"
targetNamespace="http://wsexample.com/ProductService"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://wsexample.com/ProductService"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ProductData="http://www.wsexample.com/Product/ProductData">
<wsdl:types>
<xs:schema elementFormDefault="qualified"
targetNamespace="http://wsexample.com/ProductService">
<xs:import schemaLocation="Product.xsd"
namespace="http://www.wsexample.com/Product/ProductData" />
</xs:schema>
</wsdl:types>
<wsdl:message name="GetProduct">
<wsdl:part name="in"
element="ProductData:GetProductRequest" />
</wsdl:message>
<wsdl:message name="GetProductRs">
<wsdl:part name="out"
element="ProductData:GetProductResponse" />
</wsdl:message>
<wsdl:portType name="ProductEndPoint">
<wsdl:operation name="GetProduct">
<wsdl:input message="tns:GetProduct" />
<wsdl:output message="tns:GetProductRs" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ProductServiceBinding"
type="tns:ProductEndPoint">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<wsdl:operation name="GetProduct">
<wsdl:input>
<soap:body parts="in"
use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body parts="out"
use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ProductEndpointService">
<wsdl:port name="ProductServiceEndPointPort"
binding="tns:ProductServiceBinding">
<soap:address location="http://wsexample.com/ProductService" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
So after all that modeling the message that will flow between the client and server will look like this:
Request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prod="http://www.wsexample.com/Product/ProductData">
<soapenv:Header/>
<soapenv:Body>
<prod:GetProductRequest>
<prod:Product>
<prod:ProductCode>12345678</prod:ProductCode>
</prod:Product>
</prod:GetProductRequest>
</soapenv:Body>
</soapenv:Envelope>
Response:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prod="http://www.wsexample.com/Product/ProductData">
<soapenv:Header/>
<soapenv:Body>
<prod:GetProductResponse>
<prod:Product>
<prod:ProductCode>12345678</prod:ProductCode>
<!--Optional:-->
<prod:ProductDescription>A Basic product for kids to teach them how to count. </prod:ProductDescription>
</prod:Product>
</prod:GetProductResponse>
</soapenv:Body>
</soapenv:Envelope>
Now you can use the WSDL and XSD to implement the web service using this Netbeans tutorial and guide.. Its very simple really just start a new web project in netbeans then right click the project and add new file then just select the web service from WSDL file.
See the screen shot below:
Top down summary:
Top down requires you to do a lot of modelling and planning up front. However you are in complete control. This allows you to decide how the data is going to flow between client and server. It allows you to modify everything to your exact requirements. However it requires a lot of work before hand.
The biggest benefit from me is that I can design a WSDL and XSD that abstracts the data away from the providing systems into something more generic. This become important in integration projects.
Bottom Up:
The bottom up approach allows you to generate the artifacts I created above from java code. There is a excellent tutorial here that will show you all the details. However Java allows you to add annotations to a class that then exposes the class and its method as a web service.
So by taking a class and adding annotations you turn that class into a web service. See the code below for a quick and dirty example:
#Webservice
public Class CalculatorWS
{
#WebMethod
public int add(#WebParam(name = "i") int i, #WebParam(name = "j") int j) {
int k = i + j;
return k;
}
}
If you follow the tutorial you will probably go from code to fully working web service in a couple of minutes. Quick and easy.
Bottom Up Summary:
You have very little control over how your WSDL and XSD will look and behave. In some cases this approach will bind you tightly to the underlying model. It really depends on how you code it. So with bottom up approach you can have a prototype in minutes but the message flowing up and down might not be exactly what you had in mind.
IMPORTANT TIP:
Download a copy of SOAPUI it is really the best tool to use to test and even create mock services. If you are serious about using web services then get it now.
Hope this helps you down the rabbit hole.
Related
I'm developing a SOAP based Webservice API which would be used by a third party system. WSDL file and endpoint URL would be shared with them and they invoke my Web service by passing an input parameter and get the response back
So far, I have created the Web Service API including WSDL, Services Classes, Helper Classes, DAO, Ibatis) and tested using SOAP UI by passing the input parameter, the request hits the databse and returning the response fine. Attached the WSDL file and SOAP request and response.
I got two questions,
The 3rd Party system is asking for an API documentation and SOAP Envelope. What should I give?
The 3rd party system has to invoke my service by passing the input parameter sQuoteRef. How would they usually do it? I'm not concerned about the client code here but how would the request from 3rd party look like and what changes I should make in my WSDL or Java classes to receive the input parameter and pass on to my service class?
Any inputs would be helpful in completing my task. Many Thanks!
WSDL File
<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions name="EmpService" targetNamespace="http://emp.provider.integration.gi.sample.ie/EmpService/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Emp.provider.integration.gi.sample.ie/EmpService/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xsd:schema targetNamespace="http://Emp.provider.integration.gi.sample.ie/EmpService/">
<xsd:element name="EmpRequestVO">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="sQuoteRef" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="EmpResponseVO">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="0" name="sQuoteStatus" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="GetEmpTransactionSoapIn">
<wsdl:part element="tns:EmpRequestVO" name="parameters"/>
</wsdl:message>
<wsdl:message name="GetEmpTransactionSoapOut">
<wsdl:part element="tns:EmpResponseVO" name="parameters"/>
</wsdl:message>
<wsdl:portType name="EmpServiceSoap">
<wsdl:operation name="getEmpTransaction">
<wsdl:input message="tns:GetEmpTransactionSoapIn"/>
<wsdl:output message="tns:GetEmpTransactionSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="EmpServiceSoap" type="tns:EmpServiceSoap">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getEmpTransaction">
<soap:operation soapAction="getEmpTransaction" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="PLUSEmpServices">
<wsdl:port binding="tns:EmpServiceSoap" name="EmpServiceSOAP">
<soap:address location="http://localhost:9080/WebServices/services/EmpServiceSOAP"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
End Point URL
http://localhost:9080/PLUSEmpServices/services/EmpServiceSOAP
SOAP REQUEST in SOAP UI
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:rtw="http://emp.provider.integration.gi.sample.ie/EmpService/">
<soapenv:Header/>
<soapenv:Body>
<rtw:EmpRequestVO>
<sQuoteRef>12123118</sQuoteRef>
</rtw:EmpRequestVO>
</soapenv:Body>
</soapenv:Envelope>
SOAP RESPONSE in SOAP UI
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header/>
<soapenv:Body>
<p900:EmpResponseVO xmlns:p900="http://emp.provider.integration.gi.sample.ie/EmpService/">
<sQuoteStatus>Active</sQuoteStatus>
</p900:EmpResponseVO>
</soapenv:Body>
</soapenv:Envelope>
The 3rd Party system is asking for an API documentation and SOAP Envelope. What should I give?
To start APIs integration with external parties, your clients require a technical API document that will be a reference to complete APIs integration and a base for any technical communication between the teams. The technical document may includes the following details:
Brief description for different available web-services APIs and their requirements.
APIs communications flow. This will be useful in case the clients need to call more than one services in specific sequence. Including flow diagram will be possible option to explain the system flow.
Test environment details like WSDL URL and access credentials like username, password, agent code, etc.
Detailed description for all fields needed to send a valid request to the server. Fields details may include the following:
a. Filed name.
b. Description.
c. Data Type.
d. Max length.
e. Mandatory, Optional or Conditional.
f. Possible values if any.
All possible response codes a long with their description sent by server API to client API which indicates the successful or failure of transaction process(s). For example (0000 means Success, E001 means validation error, E002 system error, 9999 unknown error, etc.).
Note: Response codes should cover various rejection cases.
Security Section that explain how the data is exchange securely between client and server application.
a. Mention additional Encryption mechanism for part or all request data if any.
b. Communication type with the client wither it is over VPN or accessed public
over https URL. Note the URL you mentioned in your question is deployed in your local machine and it will not be available publicly.
Sample SOAP request(s) and response(s) xml format for all available API’s web methods.
Mention any additional rules or constrains on APIs connectivity.
The 3rd party system has to invoke my service by passing the input parameter sQuoteRef. How would they usually do it? I'm not concerned about the client code here but how would the request from 3rd party look like and what changes I should make in my WSDL or Java classes to receive the input parameter and pass on to my service class?
If I understand you correctly your are asking how should I change WSDL or Java classes to accept client request correctly ? Usually the server side API has the upper hand in XML format need to be exchanged and in your case it should be mentioned in WSDL. So the client will create a valid request as per definition mentioned in server WSDL URL.
Further reading that my be useful on how to generate WSDL from Java classes:
Eclipse WSDL generator (from java class)?
SOAP fault handling in java
I'm working on a JAX-WS service with Apache CXF which takes its type definitions from two sources. An XSD schema file defines various types in a .../types/ namespace and there are the matching java classes with JAXB annotations. The endpoint is defined in a Java inteface with the #WebService related annotations inside the .../service/ namespace. The WSDL is generated by Apache CXF and it uses the type definitions from the XSD schema file together with generated type definitions for the request/response messages and parameters, taken from the #WebService endpoint.
I've run into the following validator error about one of the Apache CXF generated types inside the .../service/ namespace.
Caused by: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 10; cvc-elt.1: Cannot find the declaration of element 'ser:subscriberId'.
The endpoint is defined like this in the .../service/ namespace:
#WebService(name="gatewayService",
targetNamespace="http://www.mydomain.com/gateway/schema/service/")
public interface GatewayEndpoint {
// ...
#WebMethod(operationName="addService")
#XmlElement(required=true) public Response addService(
#XmlElement(required=true) #WebParam(name="subscriberId") long subscriberId,
#XmlElement(required=true) #WebParam(name="service") Service service)
throws GatewayException;
// ...
}
The JAX-WS endpoint is defined in a spring configuration file as such:
<!-- Apache CXF endpoint -->
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<jaxws:endpoint id="gatewayndpoint" implementor="#gatewayEndpointImpl" address="/gateway">
<jaxws:schemaLocations>
<jaxws:schemaLocation>classpath:/schemas/gateway_schema.xsd</jaxws:schemaLocation>
</jaxws:schemaLocations>
<jaxws:properties>
<entry key="schema-validation-enabled" value="true" />
</jaxws:properties>
</jaxws:endpoint>
The gateway_schema.xsd contains various complexType definitions among them the Service definition in the .../types/ namespace:
<xs:complexType name="Service">
<xs:sequence>
<xs:element name="name">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="deviceLimit" type="xs:int"/>
<xs:element maxOccurs="unbounded" minOccurs="0" name="subscription" nillable="true" type="gateway:Subscription"/>
<xs:element maxOccurs="unbounded" minOccurs="0" name="package" nillable="true" type="gateway:Package"/>
</xs:sequence>
</xs:complexType>
And the matching JAXB annotated class is:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Service")
public class Service {
#XmlElement(required=true)
private String name;
private int deviceLimit;
#XmlElement(name="subscription", nillable=true)
private List<Subscription> subscriptions;
#XmlElement(name="package", nillable=true)
private List<Package> packages;
//.. getters and setters
}
Everything is packaged in a war file and after deployment the generated WSDL looks like this:
<?xml version="1.0" ?>
<wsdl:definitions
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://www.mydomain.com/gateway/schema/service/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:ns2="http://schemas.xmlsoap.org/soap/http"
xmlns:ns1="http://www.mydomain.com/gateway/schema/services/"
name="GatewayService"
targetNamespace="http://www.mydomain.com/gateway/schema/service/">
<wsdl:types>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:gateway="http://www.mydomain.com/gateway/schema/types/"
elementFormDefault="qualified"
targetNamespace="http://www.mydomain.com/gateway/schema/types/"
version="1.0">
<!--
Various type definitions available in the gateway_schema.xsd
Among them the typ:Service definition
-->
</xs:schema>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.mydomain.com/gateway/schema/services/"
xmlns:ns0="http://www.mydomain.com/gateway/schema/types/"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://www.mydomain.com/gateway/schema/services/">
<xsd:import namespace="http://www.mydomain.com/gateway/schema/types/"></xsd:import>
<!--
Definitions generated by Apache CXF
-->
<xsd:element name="addService" type="tns:addService"></xsd:element>
<xsd:complexType name="addService">
<xsd:sequence>
<xsd:element name="subscriberId" type="xsd:long"></xsd:element>
<xsd:element name="service" type="ns0:Service"></xsd:element>\
</xsd:sequence>
</xsd:complexType>
<!-- .... -->
</xsd:schema>
</wsdl:types>
<wsdl:message name="addService">
<wsdl:part element="tns:addService" name="parameters"></wsdl:part>
</wsdl:message>
<!... rest of messages, portTypes, bindings and wsdl:service -->
</wsdl:definitions>
A SoapUI generated request for this service is this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://www.mydomain.com/gateway/schema/service/" xmlns:typ="http://www.mydomain.com/gateway/schema/types/">
<soapenv:Header/>
<soapenv:Body>
<ser:addService>
<ser:subscriberId>100</ser:subscriberId>
<ser:service>
<typ:name>12345678</typ:name>
<typ:deviceLimit>1</typ:deviceLimit>
<!--Zero or more repetitions:-->
<typ:subscription name="a"/>
<!--Zero or more repetitions:-->
<typ:package name="b"/>
</ser:service>
</ser:addService>
</soapenv:Body>
</soapenv:Envelope>
An the validator responds with this validation error, about the subscriberId element:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Unmarshalling Error: cvc-elt.1: Cannot find the declaration of element 'ser:subscriberId'.</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
It's strange to me that the validator fails for one of the generated types corresponding to a method call parameter which is a simple long. Anyone have a hint what might be the problem?
Apache CXF version is 2.7.10 and I'm using Java 1.7, so I guess it's using whatever JAXB implementation is in there.
You have a namespace problem... In the wsdl, you have the namespace of "http://www.mydomain.com/gateway/schema/services/" for the addService/subscriberId elements, but you are sending "http://www.mydomain.com/gateway/schema/service/". Note the lack of "s" on the end.
I have a WSDL for a soap-based web service that contains a custom header:
<message name="Request">
<part element="common:Request" name="Request"></part>
<part element="common:myHeader" name="Header"></part>
</message>
<operation name="processRequest">
<soap:operation soapAction=""/>
<input>
<soap:body parts="Request" use="literal"/>
<soap:header message="tns:Request" part="Header" use="literal"></soap:header>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
The header type is defined in a separate schema file:
<xs:element name="myHeader" nillable="false" type="tns:myHeaderType"/>
<xs:complexType name="myHeaderType">
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="JobID" type="tns:JobIDType" minOccurs="1" maxOccurs="1"/>
<xs:element name="TransactionID" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
Furthermore, I am validating against the definition of myHeaderType to make sure that the required elements are there, formatting constraints are met, etc. This all appears to be working correctly, in that well-formed requests are accepted and incorrectly formatted requests are rejected.
My problem arises with a consumer who uses Apache Axis (hidden behind a proprietary tool) to generate their web-service client. As described in another StackOverflow question here, Axis inserts some optional attributes on myHeader that are allowed by the SOAP standard (as nearly as I can tell):
<soapenv:Header>
<com:myHeader soapenv:mustUnderstand="0" soapenv:actor="">
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
<JobID>myJobId</JobID>
<TransactionID>myTransactionId</TransactionID>
</com:myHeader>
</soapenv:Header>
Because of the tool that my consumer is using, it is not feasible to modify the Axis-generated stubs to omit these attributes, as has been suggested elsewhere. Furthermore, it seems these attributes should be allowed by my service, if I'm going to claim to be a soap service. My question is, how can I modify my header definition to accommodate these optional attributes, and ideally plan for attributes that I might not be anticipating. Is there a standard type that I can extend for my header type definition, or a general best practice for this situation?
I was able to find a couple of solutions to my problem today. They both solve the problem, but I'm not confident in my judgement of which is really the better of the two, so I'll present them both here.
Both solutions center around modifying the definition of myHeaderType so that it can accommodate the unanticipated SOAP-defined attributes.
Within the SOAP WSDL schema definition (http://schemas.xmlsoap.org/wsdl/), there is a type called tExtensibleAttributesDocumented that includes the following very flexible attribute definition:
<xs:anyAttribute namespace="##other" processContents="lax"/>
By extending this abstract type, I was able to incorporate this liberal allowance for unanticipated attributes into my type. Here is the resulting code:
<xs:complexType name="myHeaderType">
<xs:complexContent>
<xs:extension base="wsdl:tExtensibleAttributesDocumented">
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="JobID" type="tns:JobIDType" minOccurs="1" maxOccurs="1"/>
<xs:element name="TransactionID" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Note that this does not check the contents of mustUnderstand or actor, and allows other attributes, including complete garbage, so long as it comes from a namespace that I have defined in my XML request.
The other alternative was to directly include the <xs:anyAttribute> in my type:
<xs:complexType name="myHeaderType">
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="JobID" type="tns:JobIDType" minOccurs="1" maxOccurs="1"/>
<xs:element name="TransactionID" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
This has basically the same effect, as far as I was able to determine.
If there are any subtle differences between these solutions that I'm not aware of, I'd love to hear about it. If there is an accepted standard for this situation, I was not able to find it. Another weakness of this solution is that I was not able to get the attributes to validate against their definitions in the schema. Changing the processContents attribute to strict prevented even the well-defined mustUnderstand and actor attributes from being processed.
Yes, you can modify with Altova XMLSpy editor. Use functionally for 30 days.
I have a third party webservice for which I generate a client using wsimport. Each call to the webservice completes successfully, but the response object I get back has all its fields set to null. Monitoring the network I can see that on the wire all of the XML elements in the response message have values in them, so the object should have non-null data in it. Also, a client for the same service generated with old axis1 and called with the same data returns a non-empty response. Any idea what's happening? (In case it makes any difference I'm using MOXy's implementation of JAXB).
Update: I've been able to narrow it down. The wsdl defines object in its own namespace, say http://www.acme.com/ws. The response I get from the service is
<?xml version="1.0" encoding="UTF-8"?>
... SOAP envelope ...
<ns1:opINFOWLResponse xmlns:ns1="http://www.acme.com/ws"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:responseINFOWL xsi:type="ns1:responseINFOWL">
<result>6003</result>
<ndserr/>
<transid>61437594</transid>
<descriptionerr>BLAH.</descriptionerr>
</ns1:responseINFOWL>
</ns1:opINFOWLResponse>
... SOAP closing tags ...
and is unmarshalled to a non null OpINFOWLResponse which wraps around a non null responseINFOWL object with all the fields set to null. Just for fun I've tried writing a couple of lines to unmarshal the above snippet (after stripping the SOAP overhead)
JAXBContext ctx = JAXBContext.newInstance(OpINFOWLResponse.class);
Unmarshaller u = ctx.createUnmarshaller();
OpINFOWLResponse o = (OpINFOWLResponse) u.unmarshal(new StringReader(theSnippetAbove));
ResponseINFOWL w = o.getResponseINFOWL();
and I get the same result. If I change the XML above to
<?xml version="1.0" encoding="UTF-8"?>
<ns1:opINFOWLResponse xmlns:ns1="http://www.acme.com/ws"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:responseINFOWL xsi:type="ns1:responseINFOWL">
<ns1:result>6003</ns1:result>
<ns1:ndserr/>
<ns1:transid>61437594</ns1:transid>
<ns1:descriptionerr>BLAH.</ns1:descriptionerr>
</ns1:responseINFOWL>
</ns1:opINFOWLResponse>
Everything works fine. Bummer.
Update (again): Same behaviour with both jaxb-RI and Moxy. Still have no idea what's wrong.
Update (Sep. 9): The suggestion below about namespace qualification being wrong is interesting, but I supposed wsimport would get things right. Anyway, this is my package-info.java
#XmlSchema(
namespace = "http://www.acme.com/ws",
elementFormDefault = XmlNsForm.QUALIFIED)
package it.sky.guidaTv.service.remote;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlNsForm;
and this is the relevant part of the ResponseINFOWL class
/*
* <p>Java class for responseINFOWL complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="responseINFOWL">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="result" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="descriptionerr" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="transid" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="ndserr" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="wallet" type="{http://www.acme.com/ws}t_wallet" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "responseINFOWL", propOrder = {
"result", "descriptionerr", "transid", "ndserr", "wallet" })
public class ResponseINFOWL {
#XmlElement(required = true)
protected String result;
#XmlElement(required = true)
protected String descriptionerr;
#XmlElement(required = true)
protected String transid;
protected String ndserr;
protected TWallet wallet;
// getters, setters and all.
}
I've tried playing a bit with the namespaces in package-info but still no joy.
I recently ran into the exact same problem you encountered, and it came down to the fact that the service I was contacting was returning something different from what its WSDL advertised. The service used an old version of Apache Axis (1.4) with behaviour that conflicts with current JAX-WS implementations.
In particular, the namespace on the actual response body contents was NOT what was expected by the client code generated by JAX-WS's wsimport utility. For example, the actual response looked something like this, with the serviceResponse and all its children in namespace "http://foo.com":
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<serviceResponse xmlns="http://foo.com">
<messageReturn>
<messageId>12345</messageId>
<status>Ok</status>
</messageReturn>
</serviceResponse>
</soapenv:Body>
</soapenv:Envelope>
In contrast to what was actually coming back, the client stubs generated by wsimport were expecting something like the response below, with the serviceResponse element in namespace "http://foo.com" and the contained child messageReturn element in the anonymous namespace.
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<n1:serviceResponse xmlns:n1="http://foo.com">
<messageReturn>
<messageId>12345</messageId>
<status>Ok</status>
</messageReturn>
</n1:serviceResponse>
</soapenv:Body>
</soapenv:Envelope>
Since I could not change the service I was consuming, I instead wrote a new WSDL myself that used a wrapped doc-literal binding to explicitly control the expected structure of the response (and request, of course). There is a really good article on WSDL binding types over IBM Developerworks.
The WSDL I created looked something like this:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://foo.com"
xmlns:tns="http://foo.com"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Define the XML types we need to send and receive (used by the message definitions below) -->
<wsdl:types>
<schema targetNamespace="http://foo.com" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<!-- Reusable types -->
<complexType name="ResponseType">
<sequence>
<element name="messageId" nillable="true" type="xsd:string" />
<element name="status" nillable="true" type="xsd:string" />
</sequence>
</complexType>
<complexType name="InputType">
<sequence>
<element name="firstName" nillable="true" type="xsd:string" />
<element name="lastName" nillable="true" type="xsd:string" />
<element name="command" nillable="true" type="xsd:string" />
</sequence>
</complexType>
<!-- Specific input/output elements used in wsdl:message definitions -->
<element name="serviceResponse">
<complexType>
<sequence>
<element name="messageReturn" type="tns:ResponseType" />
</sequence>
</complexType>
</element>
<element name="serviceRequest">
<complexType>
<sequence>
<element name="message" type="tns:InputType" />
</sequence>
</complexType>
</element>
</schema>
</wsdl:types>
<!-- Define the WSDL messages we send/receive (used by the port definition below) -->
<wsdl:message name="serviceResponseMessage">
<wsdl:part name="part1Name" element="tns:serviceResponse" />
</wsdl:message>
<wsdl:message name="serviceRequestMessage">
<wsdl:part name="part1name" element="tns:serviceRequest" />
</wsdl:message>
<!-- Define the WSDL port (used by the binding definition below) -->
<wsdl:portType name="ServicePort">
<wsdl:operation name="serviceOperation">
<wsdl:input message="tns:serviceRequestMessage" />
<wsdl:output message="tns:serviceResponseMessage" />
</wsdl:operation>
</wsdl:portType>
<!-- Define the WSDL binding of the port (used by the service definition below) -->
<wsdl:binding name="ServiceSoapBinding" type="tns:ServicePort">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="serviceOperation">
<wsdlsoap:operation soapAction="" />
<wsdl:input>
<wsdlsoap:body use="literal" />
</wsdl:input>
<wsdl:output>
<wsdlsoap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<!-- Finally, define the actual WSDL service! -->
<wsdl:service name="UserCommandService">
<wsdl:port binding="tns:ServiceSoapBinding" name="ServicePort">
<!-- This address is just a placeholder, since the actual target URL will be specified at runtime -->
<wsdlsoap:address location="http://localhost:8080/blah" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
With the custom WSDL, I was able to use wsimport to generate client stubs that work perfectly with the service. As well, with the wrapped doc-literal approach, I completely control the expected structure and namespace of the request/response, so I can implement multiple namespaces in that XML if necessary.
Enjoy...
Please correct me if I have your use case incorrect.
You can unmarshal:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:opINFOWLResponse xmlns:ns1="http://www.acme.com/ws"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:responseINFOWL xsi:type="ns1:responseINFOWL">
<ns1:result>6003</ns1:result>
<ns1:ndserr />
<ns1:transid>61437594</ns1:transid>
<ns1:descriptionerr>BLAH.</ns1:descriptionerr>
</ns1:responseINFOWL>
</ns1:opINFOWLResponse>
But cannot unmarshal:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:opINFOWLResponse xmlns:ns1="http://www.acme.com/ws"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:responseINFOWL xsi:type="ns1:responseINFOWL">
<result>6003</result>
<ndserr />
<transid>61437594</transid>
<descriptionerr>BLAH.</descriptionerr>
</ns1:responseINFOWL>
</ns1:opINFOWLResponse>
This means that the namespace qualification in your JAXB mappings is incorrect. The following may help:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
If you could post the class that maps to this section of XML, and the package-info class if there is one, then I can help you modify the mappings.
I had the same problem, in my case, my java service was expecting xml elements without namespace, but the service was reponsing with namespaces. I fixed by adding #XmlElement annotation setting the expected namespace and element name as follows:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MyResponseType", propOrder = { "someProp" })
public class MyResponseType {
#XmlElement(namespace = "http://www.your-namespace.com/schema/v1.0", name = "someProp")
protected Integer someProp;
}
Can any one figure out my problem is...
I'm calling a webmethod of a Java Webservice (Axis 1.4) from a .Net client. That method returns a Map object, and if i call it from an Axis client works fine, but in my c# code it´s always null.
That's the WSDL:
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="urn:http.service.enlaces.portlet.ext.com" xmlns:intf="urn:http.service.enlaces.portlet.ext.com" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns1="http://model.enlaces.portlet.ext.com" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:http.service.enlaces.portlet.ext.com">
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xml.apache.org/xml-soap">
<import namespace="urn:http.service.enlaces.portlet.ext.com"/>
<import namespace="http://model.enlaces.portlet.ext.com"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="mapItem">
<sequence>
<element name="key" nillable="true" type="xsd:anyType"/>
<element name="value" nillable="true" type="xsd:anyType"/>
</sequence>
</complexType>
<complexType name="Map">
<sequence>
<element maxOccurs="unbounded" minOccurs="0" name="item" type="apachesoap:mapItem"/>
</sequence>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="getFoldersAndBookmarksRequest" />
<wsdl:message name="getFoldersAndBookmarksResponse">
<wsdl:part name="getFoldersAndBookmarksReturn" type="apachesoap:Map" />
</wsdl:message>
<wsdl:portType name="BookmarksEntryServiceSoap">
<wsdl:operation name="getFoldersAndBookmarks">
<wsdl:input name="getFoldersAndBookmarksRequest" message="intf:getFoldersAndBookmarksRequest" />
<wsdl:output name="getFoldersAndBookmarksResponse" message="intf:getFoldersAndBookmarksResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Portlet_Bookmarks_BookmarksEntryServiceSoapBinding" type="intf:BookmarksEntryServiceSoap">
<wsdlsoap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" />
<wsdl:operation name="getFoldersAndBookmarks">
<wsdlsoap:operation soapAction="" />
<wsdl:input name="getFoldersAndBookmarksRequest">
<wsdlsoap:body use="encoded" namespace="urn:http.service.enlaces.portlet.ext.com" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</wsdl:input>
<wsdl:output name="getFoldersAndBookmarksResponse">
<wsdlsoap:body use="encoded" namespace="urn:http.service.enlaces.portlet.ext.com" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
and my c# auto-generated code:
[System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="urn:http.service.enlaces.portlet.ext.com", ResponseNamespace="urn:http.service.enlaces.portlet.ext.com")]
[return: System.Xml.Serialization.SoapElementAttribute("getFoldersAndBookmarksReturn")]
public Map getFoldersAndBookmarks() {
object[] results = this.Invoke("getFoldersAndBookmarks", new object[0]);
return ((Map)(results[0]));
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3082")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace="http://xml.apache.org/xml-soap")]
public partial class Map {
private mapItem[] itemField;
/// <comentarios/>
public mapItem[] item {
get {
return this.itemField;
}
set {
this.itemField = value;
}
}
}
I,ve seen everywhere unfortunately, i don't find the solution.
Please, there are anyone what knows it?
I've faced the same problem a while ago. This happens when you try to get an array of elements through an axis webservice with a .net client.
The problem is "name=item" part of this line :
<element maxOccurs="unbounded" minOccurs="0" name="item" type="apachesoap:mapItem"/>
Try changing in that particular line "item" to "mapItem". Try one of these :
<element maxOccurs="unbounded" minOccurs="0" name="mapItem" type="apachesoap:mapItem"/>
or
<element maxOccurs="unbounded" minOccurs="0" name="key" type="apachesoap:mapItem"/>
or
<element maxOccurs="unbounded" minOccurs="0" name="value" type="apachesoap:mapItem"/>
So it very late to help you but I recently was running into the same problem.
Firstly I am using Eclipse to create a web service. The problem for me was that the wsdd generated was using the 'document/literal(wrapped)' style. Changing that to 'RPC' fixed the issue. No more nulls.
So maybe if you change your encoding to RPC that might fix your issue too.
And this is why web services generated from code are almost never interoperable :)
One good way of working around this is to make the wsdl first, and define a nice clear little bit of XSD, that should map nicely into both .Net and java. An alternative is something other than axis 1.4 (yech, the pain) for the server if you have any control over that.
Finally, try massaging the signatures in the java code, try replacing List with MapItem[], or vice versa, make sure you don't have Map anywhere in a return object or a parameter.
Reviewing your generated wsdl again, I'd say this is probably because of the xsd:anyType for the key/value part of the mapItem.
I think that's what is generated by axis if you have a java Object in a parameter. Trust me, you don't want that. Make it a string, or a complex type, or an Integer, but an Object can only imply open ended xml (xsd:anyType) and not many clients no how to parse that.
I faced that, and I had to change WSDL file so:
<wsdlsoap:body use="encoded" ...
to
<wsdlsoap:body use="literal" ...
Only to perform the proxy generation.
I faced same issue. My solution is to remove the Namespace in auto-generated function.
This is my function:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.service-now.com/incident/getRecords", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlArrayAttribute("getRecordsResponse", Namespace = "")]
[return: System.Xml.Serialization.XmlArrayItemAttribute("getRecordsResult", Form = System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable = false)]
public getRecordsResponseGetRecordsResult[] getRecords([System.Xml.Serialization.XmlElementAttribute("getRecords", Namespace = "http://www.service-now.com/incident")] getRecords getRecords1)
{
object[] results = this.Invoke("getRecords", new object[] {
getRecords1});
return ((getRecordsResponseGetRecordsResult[])(results[0]));
}
I removed the Namespace in this line. Bacause when I test the web service via SoapUI, I realized that the response object has no namespace. But auto-generated code has namespace.
[return: System.Xml.Serialization.XmlArrayAttribute("getRecordsResponse", Namespace = "")]
SoapUI Response was as following:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<getRecordsResponse>
<getRecordsResult>
<active>0</active>
</getRecordsResult>
</getRecordsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>