I'm having a bit of trouble getting Visual Studio to play nicely with my Axis2 web service. The problem is very strange, although not a show stopper. If anything it is just annoying, and I'd really appreciate a way around this.
The problem is that when using the web service in C# code, none of the parameters or return values are in their native data types. So instead of just being able to call, for example:
string timeDiff = MyWebService.GetServerTimeDifference(LocalTime)
Console.WriteLine(timeDiff);
I have to write
MyWebService.GetServerTimeDifference request = new MyWebService.GetServerTimeDifference();
request.#LocalTime = LocalTime;
Console.WriteLine(MyWebService.GetServerTimeDifference(request).#return);
As you can tell, this gets very annoying very quickly. The strange thing is that when creating the Web Reference to the web service, all of the data types and parameters are correctly shown in the service discovery page. I have tried modifying the WSDL file for the web service to remove anything which may be confusing visual studio, but so far I haven't been able to get this to work as it should.
I read somewhere that this is a Visual Studio and/or .Net problem in the de-serialization process, rather than a problem with the web service itself. I'm thinking this may be true, as the web service can be consumed correctly within NetBeans.
The Web Service is written in Java and hosted on an axis2 / Tomcat server, but the client software will be written in C# .Net 2.0.
Anyway - has anybody experienced this before? I have been unable to find the page where I read about the de-serialization problem again, so if anybody has anything to say which could help me out I'd very much appreciate it.
I suggest you define your WSDL using the document/literal/wrapped style, which as far as I know seems to be the best fit when you want interoperability.
This makes your service implementation behave well with WCF, that is used by Viusual Studio 2008 when you define a Service Reference.
It is possible to modify the WSDL specifikation for your service without breaking an existing implementation, but don't count on it.
The tricky part, though, is that you have to use some special lingo in your WSDL so that WCF will not snap out of generating nice wrappers as you requested. In your case, the automatically generated client code seems to fall back to the document/literal style, where you create and initialize "structs" that you feed to your client service method.
In essence, what you need to do is to:
Define your wsdl:types using XML Schema element.
Stick to a reasonable subset of XML Schema constructs when defining types (see the WCF documentation for a list).
Declare all elements of object-type (such as xsd:token, xsd:NMTOKEN, xsd:base64Binary, ...) as nillable="true" - plain types such as xsd:int should not be nillable.
Be prepared that the first element in a sequence used as an answer will be returned from the service call while the rest will be passed as out parameters - this typically makes an xsd:int status a suitable candidate as first in sequence.
Define your wsdl:message using wsdl:part named parameters (not parameter, not param, it has to be parameters) and using the element attribute
Define the style of the soap:operation in the wsdl:binding as "document".
Declare wsdl:input and wsdl:output to use "literal" SOAP encoding.
Play with your WSDL file and use svcutil to generate the client code. You will get warnings if there are errors in your WSDL file and if you look into the generated code, you will see comments that may point to why the wrapping style fails.
Some code may be of use here. This is a stripped down WSDL describing a service with one method GetVersionInformation that returns the triplet {"1.0", 1, 0} - effectively being the version of the interface using major and minor version numbers.
<wsdl:definitions
targetNamespace="http://tempuri.org"
xmlns:tns="http://tempuri.org"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xsd:schema
elementFormDefault="qualified"
targetNamespace="http://tempuri.org"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Wrapper elements. Conventions apply to wrapper element names! -->
<xsd:element name="GetVersionInformation" nillable="true" type="tns:VoidType" />
<xsd:element name="GetVersionInformationResponse" nillable="true" type="tns:VersionInformationType" />
<!-- Just a void type -->
<xsd:complexType name="VoidType">
<xsd:sequence />
</xsd:complexType>
<!-- Major and minor version information -->
<xsd:complexType name="VersionInformationType">
<xsd:sequence>
<xsd:element nillable="true" minOccurs="1" maxOccurs="1" name="version" type="xsd:NMTOKEN" />
<xsd:element minOccurs="1" maxOccurs="1" name="major" type="xsd:int" />
<xsd:element minOccurs="1" maxOccurs="1" name="minor" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<!-- GetVersionInformation -->
<wsdl:message name="GetVersionInformationSoapIn">
<wsdl:part name="parameters" element="tns:GetVersionInformation" />
</wsdl:message>
<wsdl:message name="GetVersionInformationSoapOut">
<wsdl:part name="parameters" element="tns:GetVersionInformationResponse" />
</wsdl:message>
<!-- Port type -->
<wsdl:portType name="MyServicePortType">
<wsdl:operation name="GetVersionInformation">
<wsdl:input message="tns:GetVersionInformationSoapIn" />
<wsdl:output message="tns:GetVersionInformationSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MyServiceSOAP11Binding" type="tns:MyServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<wsdl:operation name="GetVersionInformation">
<wsdl:input>
<soap:body use="literal" parts="parameters" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="MyServiceSOAP12Binding" type="tns:MyServicePortType">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<wsdl:operation name="GetVersionInformation">
<wsdl:input>
<soap12:body use="literal" parts="parameters" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MyService">
<wsdl:port name="MyServiceSOAP11port" binding="tns:MyServiceSOAP11Binding">
<soap:address location="http://localhost:80/mojo/services/MyService" />
</wsdl:port>
<wsdl:port name="MyServiceSOAP12port" binding="tns:MyServiceSOAP12Binding">
<soap12:address location="http://localhost:80/mojo/services/MyService" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
You may generate client code for this WSDL, using:
svcutil /t:code /serializer:DataContractSerializer /s /out:MyService.cs /n:*,MyService /ixt MyService.wsdl
Further, calling this code from C# would be like this:
// The endpointConfigurationName must match the corresponding entry
// in app.config, with the following content:
//
// <configuration>
// <system.serviceModel>
// <bindings>
// <basicHttpBinding>
// <binding name="MyServiceSOAP11Binding" ...>
// </binding>
// .../...
// </basicHttpBinding>
// </bindings>
// <client>
// <endpoint
/// ... binding="basicHttpBinding"
// ... bindingConfiguration="MyServiceSOAP11Binding"
// ... name="MyServiceSOAP11port" />
// </client>
// </system.serviceModel>
// </configuration>
//
string endpointConfigurationName = "MyServiceSOAP11port";
string wsEndpoint = "http://localhost/mojo/services/MyService";
MyService.MyServicePortTypeClient wsClient = null;
try
{
wsClient = new MyService.MyServicePortTypeClient(endpointConfigurationName, wsEndpoint);
}
catch (InvalidOperationException ioe)
{
// Possibly a problem with the configuration
// Inform(Logging.LogLevel.WARNING, "Potential problem with configuration: " + ioe.Message);
return;
}
string wsUsername = "John";
string wsPassword = "Doe";
if (!String.IsNullOrEmpty(wsUsername) && !String.IsNullOrEmpty(wsPassword))
{
UserNamePasswordClientCredential credentials = wsClient.ClientCredentials.UserName;
credentials.UserName = wsUsername;
credentials.Password = wsPassword;
}
try
{
int major;
int minor;
string version = wsClient.GetVersionInformation(out major, out minor);
// Inform(Logging.LogLevel.DEBUG, "Service has version " + version);
}
catch (System.ServiceModel.EndpointNotFoundException enfe)
{
// string info = "Could not contact MyService: " + enfe.Message;
// Inform(Logging.LogLevel.ERROR, info);
return;
}
catch (System.ServiceModel.FaultException fe)
{
// string info = "Could not contact MyService: " + fe.Message;
// Inform(Logging.LogLevel.ERROR, info);
return;
}
While we are at it, why not also implement the service using Axis2. First, we need a service specification (services.xml in our AAR):
<serviceGroup name="MyServices">
<service name="MyService" scope="application">
<description>My Service - document/literal wrapped style, suited for .NET integration</description>
<!-- Service methods -->
<operation name="GetVersionInformation">
<messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
<actionMapping>http://tempuri.org/MyServicePortType/GetVersionInformationRequest</actionMapping>
</operation>
<!-- Use WS-Adressing, ... -->
<module ref="addressing" />
<!-- Service implementation -->
<parameter name="ServiceClass">com.mycompany.services.MyService</parameter>
</service>
<service name="MyOtherService" scope="application" >
.../...
</service>
</serviceGroup>
And our server implementation, using AXIOM:
package com.mycompany.services.MyService;
import javax.xml.stream.XMLStreamException;
import javax.xml.namespace.QName;
import org.apache.axiom.om.*;
import org.apache.axis2.context.ServiceContext;
import org.apache.log4j.Logger;
public class MyService {
public static final Integer MAJOR_VERSION = 1;
public static final Integer MINOR_VERSION = 0;
public static final String NAMESPACE = "http://tempuri.org";
public static final String NAMESPACE_ALIAS = "tns";
public static final String GET_VERSION_INFORMATION_RESPONSE_ELEMENT_NAME = "GetVersionInformationResponse";
private ServiceContext serviceContext = null;
private String serviceName = null;
private static final Logger log = Logger.getLogger("SERVICE");
public void init(ServiceContext serviceContext) throws Exception {
this.serviceContext = serviceContext;
serviceName = serviceContext.getName();
}
public OMElement GetVersionInformation(OMElement element) throws XMLStreamException {
// --- Handle request ---
String version = "" + MAJOR_VERSION + "." + MINOR_VERSION;
if (log.isDebugEnabled()) {
log.debug("Retrieving version information: " + version);
}
// --- Prepare response ---
OMFactory factory = OMAbstractFactory.getOMFactory();
OMNamespace omNs = factory.createOMNamespace(NAMESPACE, NAMESPACE_ALIAS);
//
OMElement response = factory.createOMElement(GET_VERSION_INFORMATION_RESPONSE_ELEMENT_NAME, omNs);
{
OMElement value;
{
value = factory.createOMElement("version", omNs);
value.addChild(factory.createOMText(value, version));
response.addChild(value);
}
{
value = factory.createOMElement("major", omNs);
value.addChild(factory.createOMText(value, "" + MAJOR_VERSION));
response.addChild(value);
}
{
value = factory.createOMElement("minor", omNs);
value.addChild(factory.createOMText(value, "" + MINOR_VERSION));
response.addChild(value);
}
}
return response;
}
}
Axis2 and Axiom are really nice to work with. If you are having problems to generate your C# client, revisit your WSDL - it is unlikely that the problem resides with Axis2. By the way, the "Adressing" module that we refer to in the service configuration is usually added by default, but there are other modules that may be used to handle other parts of the WS-I standard.
I read somewhere that this is a Visual
Studio and/or .Net problem in the
de-serialization process, rather than
a problem with the web service itself.
I'm thinking this may be true, as the
web service can be consumed correctly
within NetBeans.
I have had this problem before - it's a .Net problem. My approach was to take a sledgehammer to the ant as it were and re-write the service in .Net
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
Below is a toy example of a simple service using javax.ws. I want to get the service URL, callable from a web browser or curl.
This is the toy service code:
package packagename;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#WebService
#Path("/service")
public class testserver
{
#GET
#Path("/test")
#WebMethod
public String test()
{
return "<html>Test text here</html>";
}
}
And this is the service deployer function:
package packagename;
import javax.xml.ws.Endpoint;
public class deploy
{
public static void main(String [] args)
{
String endpointURL = "http://localhost:7777/";
Endpoint.publish(endpointURL,new testserver());
}
}
I run the java file via bash without errors.
Shouldn't navigating to http://localhost:7777/service/test produce the text of the test() function? I am getting a Server not found error from my browser.
Below is the wsdl file at http://localhost:7777/?wsdl. Is the information I am looking for somewhere here? I have tried some urls by getting information from below (testserverService, etc) without success.
<!-- Published by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e.
-->
<!-- Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e.
-->
<definitions targetNamespace="http://packagename/" name="testserverService">
<types>
<xsd:schema>
<xsd:import namespace="http://packagename/" schemaLocation="http://localhost:7777/?xsd=1"/>
</xsd:schema>
</types>
<message name="test">
<part name="parameters" element="tns:test"/>
</message>
<message name="testResponse">
<part name="parameters" element="tns:testResponse"/>
</message>
<portType name="testserver">
<operation name="test">
<input wsam:Action="http://packagename/testserver/testRequest" message="tns:test"/>
<output wsam:Action="http://packagename/testserver/testResponse" message="tns:testResponse"/>
</operation>
</portType>
<binding name="testserverPortBinding" type="tns:testserver">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="test">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="testserverService">
<port name="testserverPort" binding="tns:testserverPortBinding">
<soap:address location="http://localhost:7777/"/>
</port>
</service>
</definitions>
I am guessing the answer is very simple or I am making gross syntax errors in my code.
Can you help ?
You are mixing both SOAP and REST APIs, which is NOT correct. You can't use them together for the same endpoint.
javax.jws.* package (called as JAX-WS) represents SOAP API
javax.ws.rs.* package (called as JAX-RS) represents REST API
You need to understand the difference between SOAP & REST web services. You can look at here for more details on these concepts.
Assuming that you are looking for REST services implementation, in general, REST services are deployed into servers (like Tomcat, Jetty, Weblogic), but if you need to run them standalone look here
This problem has had me stumped for almost two days now, I really need some help figuring it out.
I have used wsimport to generate code from two different .wsdl files for a Java project.
The first service works just fine but for some reason the response from the second service cannot be unmarshalled to a response object.
Working service:
#WebMethod(action = "[actionName]")
#WebResult(name = "getSimpleCompanyInfoResponse", partName = "getSimpleCompanyInfoResponse")
public GetSimpleCompanyInfoResponse getSimpleCompanyInfo(
#WebParam(name = "getSimpleCompanyInfoRequest", partName = "getSimpleCompanyInfoRequest") GetSimpleCompanyInfoRequest getSimpleCompanyInfoRequest);
Response POJO:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "getSimpleCompanyInfoResponse", propOrder = {
//variables
})
public class GetSimpleCompanyInfoResponse {
//variables
}
Response XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:getSimpleCompanyInfoResponse>
<getSimpleCompanyInfoResponse>
//variables
</getSimpleCompanyInfoResponse>
</ns1:getSimpleCompanyInfoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
NOT working service:
#WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
#WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
public PersonnelInfoResponse personnelInfo(
#WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);
Response POJO:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "PersonnelInfoResponse", propOrder = {
//variables
})
public class PersonnelInfoResponse {
//variables
}
Response XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:PersonnelInfoResponse>
//variables
</ns1:PersonnelInfoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Using -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true or monitoring with Wireshark I can see the Response envelope from the second service coming through just fine and unmarshalling doesn't throw any exceptions but in the end PersonnelInfoResponse is null.
The only difference I can see is that the second service response payload in the XML is missing the outer element which seems to be the problem. However, I do not know how to "fix" it so it doesn't look for the outer element.
If anything was unclear or missing please let me know and I'll try to give you all the information.
EDIT:
No, I unfortunately don't have any control over the service itself, I only have the .wsdl and .xsd.
I'm calling the service like this:
ReportsControllerPortType port = new ReportsControllerService().getReportsControllerPort();
PersonnelInfoRequest request = new PersonnelInfoRequest();
//fill the required fields in the request, username, password, etc.
PersonnelInfoResponse response = port.personnelInfo(request);
The client-side service stubs (ReportsControllerService & ReportsControllerPortType) are also automatically generated by wsimport according to the .wsdl and .xsd.
EDIT 2:
Removing the operation name doesn't work, the service fails to initialize. Following are the definitions from both .wsdl-s:
Working service:
<wsdl:message name="getSimpleCompanyInfoRequest">
<wsdl:part name="getSimpleCompanyInfoRequest" type="tns:getSimpleCompanyInfoRequest" />
</wsdl:message>
<wsdl:message name="getSimpleCompanyInfoResponse">
<wsdl:part name="getSimpleCompanyInfoResponse" type="tns:getSimpleCompanyInfoResponse" />
</wsdl:message>
<wsdl:portType name="MonitoringControllerPortType">
<wsdl:operation name="getSimpleCompanyInfo">
<wsdl:input message="tns:getSimpleCompanyInfoRequest" />
<wsdl:output message="tns:getSimpleCompanyInfoResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MonitoringControllerBinding" type="tns:MonitoringControllerPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="getSimpleCompanyInfo">
<soap:operation soapAction="[domain]/#getSimpleCompanyInfo" style="rpc" />
<wsdl:input>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MonitoringControllerService">
<wsdl:port name="MonitoringControllerPort" binding="tns:MonitoringControllerBinding">
<soap:address location="[serviceUri]" />
</wsdl:port>
</wsdl:service>
Not working service:
<wsdl:message name="PersonnelInfoRequest">
<wsdl:part name="PersonnelInfoRequest" type="tns:PersonnelInfoRequest" />
</wsdl:message>
<wsdl:message name="PersonnelInfoResponse">
<wsdl:part name="PersonnelInfoResponse" type="tns:PersonnelInfoResponse" />
</wsdl:message>
<wsdl:portType name="ReportsControllerPortType">
<wsdl:operation name="PersonnelInfo">
<wsdl:input message="tns:PersonnelInfoRequest" />
<wsdl:output message="tns:PersonnelInfoResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ReportsControllerBinding" type="tns:ReportsControllerPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="PersonnelInfo">
<soap:operation soapAction="[domain]/#PersonnelInfo" style="rpc" />
<wsdl:input>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ReportsControllerService">
<wsdl:port name="ReportsControllerPort" binding="tns:ReportsControllerBinding">
<soap:address location="[serviceUri]" />
</wsdl:port>
</wsdl:service>
EDIT 3:
ReportsControllerService and MonitoringControllerService extend javax.xml.ws.Service and contain the definitions of the .wsdl schema location and namespace used. The service class returns a PortType object as you can see:
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
*/
#WebServiceClient(name = "ReportsControllerService", targetNamespace = "[namespaceUri]", wsdlLocation = "[wsdlUri]")
public class ReportsControllerService extends Service {
#WebEndpoint(name = "ReportsControllerPort")
public ReportsControllerPortType getReportsControllerPort() {
return super.getPort(new QName("[namespaceUri]", "ReportsControllerPort"), ReportsControllerPortType.class);
}
}
ReportsControllerPortType is an interface which contains methods for every operation endpoint that exists in the service
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
*/
#WebService(name = "ReportsControllerPortType", targetNamespace = "[namespaceUri]")
#SOAPBinding(style = SOAPBinding.Style.RPC)
#XmlSeeAlso({ObjectFactory.class})
public interface ReportsControllerPortType {
#WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
#WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
public PersonnelInfoResponse personnelInfo(
#WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);
}
}
The thing is, all of those classes are automatically generated by JAX-WS (as you can see from the comments) based on the .wsdl schema. The implementation is abstracted somewhere inside the JDK and I don't have control over that either. Yes, I can refactor the code so I bypass JAX-WS but as I understand it, this is supposed to be like a de facto standard way to consume .wsdl-based SOAP services.
The project uses Spring as a base-framework and I have already confirmed both services will work when I use Spring-WS instead so I can refactor but I want to understand why this way isn't working.
I believe I may have found out why your webservice is misbehaving. According to the specification, an RPC webservice must fulfill the following criteria in its soap binding (i.e. the #SOAPBinding annotation you have there)
A style of RPC: check
A use of LITERAL: check
A parameterStyle of WRAPPED: From the description you've given, it would appear that WRAPPED is not the case here, seeing as you're receiving a naked PersonnelInfoResponse (and possibly sending a naked PersonnelInfoRequest) without any wrapping indicates that the service itself is broken.
An excerpt from the JAX-WS spec:
Use of RPC style requires the use of WRAPPED parameter style. Deviations from this is an error
There is one obvious difference between your 2 calls :
You should try to remove operationName = "PersonnelInfo" from your second call which is not present in the first working one.
I'm working on a Java 6 application server which has a web service for receiving a SOAP messages containing an HL7 message. The Java application runs on Glassfish 3.1. The client is a third-party developed C# application (which runs on the Microsoft .net 4.0 framework) and it is sending these SOAP messages to the Java server.
My initial issue was that the client was unable to parse the WSDL generated by the server. I have since resolved that by implementing my own custom WSDL and tuning it accordingly. This allowed the client to parse the WSDL and send SOAP messages to my Java server application.
However, each time a message is received on the server side, the parameter (named "putXML") is receiving a null value.
The Glassfish server log shows the following when a message is received:
Received WS-I BP non-conformant Unquoted SoapAction HTTP header: http://MyProject.MyPackage/putHL7Data
Received Message: null
Here is the custom WSDL that I created and associated with my SOAP web service:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions
targetNamespace="http://MyProject.MyPackage/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:tns="http://MyProject.MyPackage/"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsp="http://www.w3.org/ns/ws-policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://MyProject.MyPackage/">
<s:element name="putHL7Data">
<s:complexType>
<s:sequence>
<s:element name="putXML" type="s:string" minOccurs="0" maxOccurs="1"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="putHL7DataResponse">
<s:complexType>
<s:sequence>
<s:element name="return" type="s:string" minOccurs="0" maxOccurs="1"/>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="putHL7DataSoapIn">
<wsdl:part name="parameters" element="tns:putHL7Data"/>
</wsdl:message>
<wsdl:message name="putHL7DataSoapOut">
<wsdl:part name="parameters" element="tns:putHL7DataResponse"/>
</wsdl:message>
<wsdl:portType name="MyHandlerSoap">
<wsdl:operation name="putHL7Data">
<wsdl:input message="tns:putHL7DataSoapIn"/>
<wsdl:output message="tns:putHL7DataSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MyHandlerSoap" type="tns:MyHandlerSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="putHL7Data">
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MyHandler">
<wsdl:port name="MyHandlerPort" binding="tns:MyHandlerSoap">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
And here is the Java web service:
#WebService(serviceName = "MyHandler", wsdlLocation = "WEB-INF/wsdl/MyHandler.wsdl")
public class MyHandler {
#WebMethod(operationName = "putHL7Data")
public String putHL7Data(#WebParam(name = "putXML") String xml) {
// Handle message
}
}
Is there anything I am doing wrong?
What can I do to fix the Java web service so that it properly receives a non-null value?
Is this an issue with the client? If so, would I need to create some sort of interceptor?
Update
Today I tried creating a quick C# client which uses my Java SOAP web service. Below is the code:
namespace TestSoap
{
class Program
{
static void Main(string[] args)
{
ServiceReference1.MyHandlerSoapClient ws = new ServiceReference1.MyHandlerSoapClient();
string result = ws.putHL7Data("Test");
Console.WriteLine("Response: " + result);
Console.ReadLine();
}
}
}
When I run this client, I receive the same null value in the parameter when I was expecting to see the Test string. Also, I'm expecting result to contain a response string but it too is returning a null value.
Remember, I cannot modify the third-party C# client application. Is there anything I can do on the Java end?
Update 2
I recently added a handler chain class which is capturing and logging the raw SOAP messages. The message being sent by the client looks like this:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Header/>
<soap:Body>
<putHL7Data xmlns="http://MyProject.MyPackage/">
<putXML>... Encoded XML Here ...</putXML>
</putHL7Data>
</soap:Body>
</soap:Envelope>
After getting pointed in the right direction by #dlawrence, I was able to solve my issue. As I mentioned in the question, I still needed to use a custom built wsdl. I only needed to make a few changes to the wsdl and the Java code to solve the issue.
Here's a diff representing my changes to the wsdl:
--- /tmp/a 2011-09-19 15:05:21.132065003 -0400
+++ /tmp/b 2011-09-19 14:41:28.302064999 -0400
## -15,11 +15,11 ##
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
- <s:schema elementFormDefault="qualified" targetNamespace="http://MyProject.MyPackage/">
+ <s:schema targetNamespace="http://MyProject.MyPackage/">
<s:element name="putHL7Data">
<s:complexType>
<s:sequence>
- <s:element name="putXML" type="s:string" minOccurs="0" maxOccurs="1"/>
+ <s:element name="putXML" type="s:string" form="qualified" minOccurs="0" maxOccurs="1"/>
</s:sequence>
</s:complexType>
</s:element>
## -47,6 +47,6 ##
<wsdl:binding name="MyHandlerSoap" type="tns:MyHandlerSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="putHL7Data">
- <soap:operation soapAction="" style="document"/>
+ <soap:operation soapAction="http://MyProject.MyPackage/putHL7Data" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
Basically this was a three part fix...
1). I needed to remove the elementFormDefault="qualified" attribute from the <s:schema> tag.
2). Then I had to add the attribute form="qualified" on my <s:element name="putXML" ...> tag.
3). Finally, I needed to make sure I had the attribute soapAction="http://MyProject.MyPackage/putHL7Data" on my <soap:operation> tag.
Here's a diff representing my changes to the Java web method:
--- /tmp/a 2011-09-19 14:57:49.582065002 -0400
+++ /tmp/b 2011-09-19 15:00:06.942065007 -0400
## -1,7 +1,7 ##
#WebService(serviceName = "MyHandler", wsdlLocation = "WEB-INF/wsdl/MyHandler.wsdl")
public class MyHandler {
#WebMethod(operationName = "putHL7Data")
- public String putHL7Data(#WebParam(name = "putXML") String xml) {
+ public String putHL7Data(#WebParam(name = "putXML", targetNamespace="http://MyProject.MyPackage/") String xml) {
// Handle message
}
}
As you can see, all I had to do was add the targetNamespace attribute to my #WebParam.
Have you tried removing the #WebParam attribute? It shouldn't be required as there is no ambiguity with your web service here and it's possible you need to set the targetNamespace in order for it to correctly find the attribute.
i have the same Message in my glassfish console. In my android project with ksoap function i changed the following code:
soapEnvelope.setOutputSoapObject(soapReq);
HttpTransportSE httpTransport = new HttpTransportSE(url,timeOut);
try{
if (headers!=null){
// original code // my headers are null
httpTransport.call("http://service.iswitch.com/", soapEnvelope,headers);
}else{
httpTransport.call("\"http://service.iswitch.com/"\", soapEnvelope);
}
SoapObject result=(SoapObject)soapEnvelope.bodyIn;
if (result.hasProperty("moveResult"))
{
....
it works ... );
the class i generated with http://www.wsdl2code.com
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>