While calling SOAP web service getting error AxisFault faultCode: 90010001 - web-services

I have created SOAP web service client from WSDL/WSDL URL, and trying to call service.
I am getting this error (error Trace)
AxisFault
faultCode: 90010001
faultSubcode:
faultString: Mandatory field is not set in EAI_SOAPINPUT; Element -> Environment.eaiCommon.BTID, Environment.eaiCommon.Header.ChannelID, Environment.eaiCommon.Header.RequestUUID, Environment.eaiCommon.Header.ServiceRequestId, Environment.eaiCommon.Header.ServiceRequestVersion
faultActor:
faultNode:
faultDetail:
{http://xml.apache.org/axis/}stackTrace:Mandatory field is not set in EAI_SOAPINPUT; Element -> Environment.eaiCommon.BTID, Environment.eaiCommon.Header.ChannelID, Environment.eaiCommon.Header.RequestUUID, Environment.eaiCommon.Header.ServiceRequestId, Environment.eaiCommon.Header.ServiceRequestVersion
at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:222)
at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:129)
at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at javax.xml.parsers.SAXParser.parse(Unknown Source)
at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
at org.apache.axis.Message.getSOAPEnvelope(Message.java:435)
at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:62)
at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
at org.apache.axis.client.Call.invoke(Call.java:2767)
at org.apache.axis.client.Call.invoke(Call.java:2443)
at org.apache.axis.client.Call.invoke(Call.java:2366)
at org.apache.axis.client.Call.invoke(Call.java:1812)
at uk.co.mclsoftware.www.HunterII.WebServices.MatchingSoapStub.match(MatchingSoapStub.java:116)
at uk.co.mclsoftware.www.HunterII.WebServices.MatchingSoapProxy.match(MatchingSoapProxy.java:50)
at com.huntermatching.test.TestClient.main(TestClient.java:14)
it is asking me for mandatory fields.
what is this error?
message portion from wsdl:
<wsdl:message name="subHeader">
<wsdl:part element="xsd:subHeader" name="subHeader" />
</wsdl:message>
<wsdl:message name="MatchSoapIn">
<wsdl:part element="tns:Match" name="parameters" />
</wsdl:message>
<wsdl:message name="MatchSoapOut">
<wsdl:part element="tns:MatchResponse" name="parameters" />
</wsdl:message>
<wsdl:portType name="MatchingSoap">
<wsdl:operation name="Match">
<wsdl:input message="tns:MatchSoapIn" />
<wsdl:output message="tns:MatchSoapOut" />
</wsdl:operation>
</wsdl:portType>
My Client java class is
public class TestMatchClient {
public static void main(String[] args) {
try {
MatchingSoapProxy matchObj = new MatchingSoapProxy();
String controlXml="TestXmlString",batchXml="TestBatchXmlString",uName ="MyUserName",pass = "MyPass";
matchObj.match(controlXml, batchXml, uName, pass);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

How to use Cloud Functions for Firebase to write a SOAP service?

I need to implement an soap web service using firebase functions.
I found a module called soap-node soap-module-github which seems promising, since it integrates with express, and firebase says it uses express for http calls, but the problem, is I don't know how to integrate that module with firebase functions since, firebase functions are the handler of the http calls made by the clients, any help would be very helpfull.
Here is the code I have managed to create so far:
var fs = require('fs'),
soap = require('soap'),
express = require('express'),
lastReqAddress;
var server = express();
service = {
StockQuoteService: {
StockQuotePort: {
GetLastTradePrice: function (args, cb, soapHeader) {
if (soapHeader)
return {
price: soapHeader.SomeToken
};
if (args.tickerSymbol === 'trigger error') {
throw new Error('triggered server error');
} else if (args.tickerSymbol === 'Async') {
return cb({
price: 19.56
});
} else if (args.tickerSymbol === 'SOAP Fault v1.2') {
throw {
Fault: {
Code: {
Value: "soap:Sender",
Subcode: {
value: "rpc:BadArguments"
}
},
Reason: {
Text: "Processing Error"
}
}
};
} else if (args.tickerSymbol === 'SOAP Fault v1.1') {
throw {
Fault: {
faultcode: "soap:Client.BadArguments",
faultstring: "Error while processing arguments"
}
};
} else {
return {
price: 19.56
};
}
},
SetTradePrice: function (args, cb, soapHeader) {},
IsValidPrice: function (args, cb, soapHeader, req) {
lastReqAddress = req.connection.remoteAddress;
var validationError = {
Fault: {
Code: {
Value: "soap:Sender",
Subcode: {
value: "rpc:BadArguments"
}
},
Reason: {
Text: "Processing Error"
},
statusCode: 500
}
};
var isValidPrice = function () {
var price = args.price;
if (isNaN(price) || (price === ' ')) {
return cb(validationError);
}
price = parseInt(price, 10);
var validPrice = (price > 0 && price < Math.pow(10, 5));
return cb(null, {
valid: validPrice
});
};
setTimeout(isValidPrice, 10);
}
}
}
};
var wsdl = fs.readFileSync(__dirname + '/../wsdl/stockquote.wsdl', 'utf-8').toString();
server = express();
soapServer = soap.listen(server, '/stockquote', service, wsdl);
here is the stockquote.wsdl:
<wsdl:definitions name="StockQuote"
targetNamespace="http://example.com/stockquote.wsdl"
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xsd:schema targetNamespace="http://example.com/stockquote.xsd" xmlns:xsd="http://www.w3.org/2000/10/XMLSchema">
<xsd:element name="TradePriceRequest">
<xsd:complexType>
<xsd:all>
<xsd:element name="tickerSymbol" type="string"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="TradePrice">
<xsd:complexType>
<xsd:all>
<xsd:element name="price" type="float"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="TradePriceSubmit">
<xsd:complexType>
<xsd:all>
<xsd:element name="tickerSymbol" type="string"/>
<xsd:element name="price" type="float"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="valid" type="boolean"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="GetLastTradePriceInput">
<wsdl:part name="body" element="xsd1:TradePriceRequest"/>
</wsdl:message>
<wsdl:message name="GetLastTradePriceOutput">
<wsdl:part name="body" element="xsd1:TradePrice"/>
</wsdl:message>
<wsdl:message name="SetTradePriceInput">
<wsdl:part name="body" element="xsd1:TradePriceSubmit"/>
</wsdl:message>
<wsdl:message name="IsValidPriceInput">
<wsdl:part name="body" element="xsd1:TradePrice"/>
</wsdl:message>
<wsdl:message name="IsValidPriceOutput">
<wsdl:part name="body" element="xsd1:valid"/>
</wsdl:message>
<wsdl:portType name="StockQuotePortType">
<wsdl:operation name="GetLastTradePrice">
<wsdl:input message="tns:GetLastTradePriceInput"/>
<wsdl:output message="tns:GetLastTradePriceOutput"/>
</wsdl:operation>
<wsdl:operation name="SetTradePrice">
<wsdl:input message="tns:SetTradePriceInput"/>
</wsdl:operation>
<wsdl:operation name="IsValidPrice">
<wsdl:input message="tns:IsValidPriceInput"/>
<wsdl:output message="tns:IsValidPriceOutput"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetLastTradePrice">
<soap:operation soapAction="http://example.com/GetLastTradePrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="SetTradePrice">
<soap:operation soapAction="http://example.com/SetTradePrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
<wsdl:operation name="IsValidPrice">
<soap:operation soapAction="http://example.com/IsValidPrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="StockQuoteService">
<wsdl:port name="StockQuotePort" binding="tns:StockQuoteSoapBinding">
<soap:address location="http://localhost:5002/stockquote"/>
</wsdl:port>
</wsdl:service>
I have googled very good I just don't find some path , I also searched google functions and their integration with soap, since firebase functions are just google cloud functions used for firebase
Peeking at the source code for node-soap, you should be able to directly pass the _requestListener to the Cloud Function's onRequest function:
exports.stockquote = functions.https.onRequest(soapServer._requestListener)
You are on the right path,
If you want the your GCF Path for the server to be http://myfunctions.domain.com/stockquote/
then your last line in the js file should be
soapServer = soap.listen(server, '/', service, wsdl) and then after that, in your Google Cloud Function index.js enter:
exports.stockquote = functions.https.onRequest(server)
You will have to make sure that your SOAP requests are going the endpoint with a trailing slash at the end. If you do not have control of the existing clients then you can add in your own URL handler that will look at the URL and add a / to the URL that your function received.
i.e.:
exports.stockquote = functions.https.onRequest( gcfURLHandler(server) );
where gcfURLHandleris defined as
function gcfURLHandler( handler ){
return (req, res ) => {
if( !req.url || !req.path ) {
req.url = "/" + (req.url || '');
}
handler( req, res )
}
}
figured this out from a comment here. (which also has other tips in the original code)
I was working on this last week and saw the unanswered question. Took a lot of digging around to finally figure it out. Hopefully this helps others looking to do the same!
You can use express with cloud functions now :
server = express();
server.listen(5002, function () {
soap.listen(server, '/stockquote', service, wsdl);
});
exports.stockquote = functions.https.onRequest(server);
Put the route in firebase.json :
"rewrites": [
{
"source": "/stockquote",
"function": "stockquote"
}
]
When testing on the client using javascript don't forget to change the endpoint to override localhost in wsdl :
var soap = require('soap');
var url = 'https://[your-project-id].firebaseapp.com/stockquote?wsdl';
var args = {tickerSymbol: 'some symbol', price: 100.0};
var options = {
'endpoint' : 'https://[your-project-id].firebaseapp.com/stockquote'
};
soap.createClient(url, options, function(err, client) {
if (err) throw err;
//print service in json
console.log(client.describe());
client.GetLastTradePrice(args, function(err, result) {
if(err)
console.log("err = "+ err.message);
console.log(result);
res.status(200).send(result);
});
});

SOAPHandler handleMessage return custom fault

I have a custom SOAPHandler and the handleMessage() is as follows :
public boolean handleMessage(SOAPMessageContext context) {
// TODO Auto-generated method stub
/* Step-1: Extract credentials from the SOAP header */
Boolean isOutbound = (Boolean) context
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
log.info("In TransportHandler.handleMessage(...) " + isOutbound);
if (!isOutbound) {
SOAPMessage soapMsg = context.getMessage();
try {
SOAPUtil soapUtil = new SOAPUtil();
Credentials credentials = soapUtil.retrieveCredentials(soapMsg);
/* Validate credentials against the directory */
SecurityUtil securityUtil = new SecurityUtil();
securityUtil.authenticateClient(credentials.getUserName(),
credentials.getPassword());
} catch (SecurityFault_Exception e) {
// TODO Auto-generated catch block
log.error(
"SecurityFault_Exception in TransportHandler.handleMessage(...)",
e);
SOAPFault securityFault = null;
try {
securityFault = soapMsg.getSOAPBody().addFault();
securityFault.setFaultString(e.getMessage());
throw new SOAPFaultException(securityFault);
} catch (SOAPException e1) {
// TODO Auto-generated catch block
log.error(
"SOAPException while handing SecurityFault_Exception in TransportHandler.handleMessage(...)",
e1);
}
} catch (RequestMessageFormatFault_Exception e) {
// TODO Auto-generated catch block
log.error(
"RequestMessageFormatFault_Exception in TransportHandler.handleMessage(...)",
e);
SOAPFault requestFormatFault = null;
try {
requestFormatFault = soapMsg.getSOAPBody().addFault();
requestFormatFault.setFaultString(e.getFaultInfo().getCustomMessage());
throw new SOAPFaultException(requestFormatFault);
} catch (SOAPException e1) {
// TODO Auto-generated catch block
log.error(
"SOAPException while handing RequestMessageFormatFault_Exception in TransportHandler.handleMessage(...)",
e1);
}
}
}
log.info("Returning from TransportHandler.handleMessage(...)");
return true;
}
For example, if someone doesn't add the security header, following is the response :
<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" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>Security header not present in the SOAP request</faultstring>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
Now in the handleMessage(...), I have wrapped the custom fault for bad header as shown :
catch (RequestMessageFormatFault_Exception e) {
// TODO Auto-generated catch block
log.error(
"RequestMessageFormatFault_Exception in TransportHandler.handleMessage(...)",
e);
SOAPFault requestFormatFault = null;
try {
requestFormatFault = soapMsg.getSOAPBody().addFault();
requestFormatFault.setFaultString(e.getFaultInfo().getCustomMessage());
throw new SOAPFaultException(requestFormatFault);
} catch (SOAPException e1) {
// TODO Auto-generated catch block
log.error(
"SOAPException while handing RequestMessageFormatFault_Exception in TransportHandler.handleMessage(...)",
e1);
}
}
As per our org. standards, I have the below faults declared in the wsdl(partially shown here) :
.
.
.
<message name="RequestMessageFormatFault">
<part name="RequestMessageFormatFault" element="sch:RequestMessageFormatFault" />
</message>
<message name="SecurityFault">
<part name="SecurityFault" element="sch:SecurityFault" />
</message>
.
.
.
<portType name="TransportInformationDelegate">
<operation name="GetTransportInformation">
.
.
<fault name="RequestMessageFormatFault" message="tns:RequestMessageFormatFault"/>
<fault name="SecurityFault" message="tns:SecurityFault"/>
</operation>
</portType>
<binding name="TransportInformationPortBinding" type="tns:TransportInformationDelegate">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="GetTransportInformation">
.
.
.
.
<fault name="RequestMessageFormatFault">
<soap:fault name="RequestMessageFormatFault" use="literal"/>
</fault>
<fault name="SecurityFault">
<soap:fault name="SecurityFault" use="literal"/>
</fault>
</operation>
How shall I ensure that the response has this fault ? I tried the SOAPFault.addDetail(...) in vain.

C# + Java service soap message interoperability, soap messages not getting deserialized in c# APP + SGEN

One of the Java webservices that I consume within my c# application has a returned type "marketCalendar" defined like following in the wsdl. WSDL's Target name space is http://www.xyz.com
<?xml version="1.0"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.xyz.com/wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.xyz.com/api" name="cscreen" targetNamespace="http://www.xyz.com/wsdl">
<wsdl:types>
<xsd:schema targetNamespace="http://www.xyz.com/api" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="getMarketCalendar">
<xsd:complexType>
</xsd:complexType>
</xsd:element>
<xsd:element name="marketCalendar">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="country" minOccurs="1" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="exchange" minOccurs="1" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="calendarDay" minOccurs="1" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="type" type="calendarDayType" use="required"/>
<xsd:attribute name="date" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="sessionID" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<!--Get information on calendars -->
<wsdl:message name="getMarketCalendarRsp">
<wsdl:part name="marketCalendar" element="marketCalendar"/>
</wsdl:message>
<wsdl:message name="getMarketCalendarReq">
<wsdl:part name="getMarketCalendar" element="getMarketCalendar"/>
</wsdl:message>
<wsdl:portType name="Cscreen_PortType">
<wsdl:operation name="getMarketCalendarRequest">
<wsdl:input message="tns:getMarketCalendarReq"/>
<wsdl:output message="tns:getMarketCalendarRsp"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Cscreen_Binding" type="tns:Cscreen_PortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getMarketCalendarRequest">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Cscreen_Service">
<wsdl:documentation>This WSDL file describes how to access the Cscreen OTC Equity Derivatives Price Discovery Platform through the SOAP API. This software was developed by Cinnober Financial Technology.</wsdl:documentation>
<wsdl:port name="Cscreen_Port" binding="tns:Cscreen_Binding">
<soap:address location="https://hostname/api/v16"/>
<!-- hostname can for example be stage.xyz.com and www.xyz.com -->
</wsdl:port>
</wsdl:service>
and corresponding C# proxy has following interpretation,
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.xyz.com")]
public partial class marketCalendar {
private marketCalendarCountry[] countryField;
private string sessionIDField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("country", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public marketCalendarCountry[] country {
get {
return this.countryField;
}
set {
this.countryField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string sessionID {
get {
return this.sessionIDField;
}
set {
this.sessionIDField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.xyz.com")]
public partial class marketCalendarCountry {
private marketCalendarCountryExchange[] exchangeField;
private string nameField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("exchange", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public marketCalendarCountryExchange[] exchange {
get {
return this.exchangeField;
}
set {
this.exchangeField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string name {
get {
return this.nameField;
}
set {
this.nameField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.xyz.com")]
public partial class marketCalendarCountryExchange {
private marketCalendarCountryExchangeCalendarDay[] calendarDayField;
private string nameField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("calendarDay", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public marketCalendarCountryExchangeCalendarDay[] calendarDay {
get {
return this.calendarDayField;
}
set {
this.calendarDayField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string name {
get {
return this.nameField;
}
set {
this.nameField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.xyz.com")]
public partial class marketCalendarCountryExchangeCalendarDay {
private calendarDayType typeField;
private string dateField;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public calendarDayType type {
get {
return this.typeField;
}
set {
this.typeField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string date {
get {
return this.dateField;
}
set {
this.dateField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.xyz.com")]
public enum calendarDayType {
/// <remarks/>
HOLIDAY,
/// <remarks/>
EXPIRATION,
}
Problem# my c# application invokes a method GetMarketCalendar on the java webservice and does see the XML response coming in but can't deserialize it back into a marketCalendar response. So I started digging by using XGen generated class.
I noticed that for types country, exchange, calendarDay - c#'s default deserializer is comparing the namespace coming in the soap response to an empty string i.e.
if (((object) Reader.LocalName == (object)id84_country && (object) Reader.NamespaceURI == (object)id2_Item)) {
where incoming is Reader.NamespaceURI = "http://www.xyz.com" and id2_Item = Reader.NameTable.Add(#""); i.e. empty. Since comparision fails, deserialization also fails. Is there any work around?
Is this a C# XMLSerializer bug or there is something wrong with the marketCalendar definition in wsdl?

JAXWS / JAXB doesn't bind attributes of references Object from seperate jar

Problem:
When JAXB unmarshalls the xml into the object tree, the attributes of objects from a seperate jar (and schema) are not set and remain null.
See the code below. On unmarshalling, the attributes of the MeldingType class remain NULL, even though the SOAP message has filled the 'code' and 'melding' child-elemens in the 'meldingen' elements.
If I create a 'local' version of MeldingType in the .war and also place the .xsd definition of MeldingType in the out.xsd, everything works perfectly. :(
How can I work with a seperate jar, so that I can share common JAXB objects from common .xsd's?
Situation
I have a war and a jar file.
The .war contains a class 'RequestType', package-info, out.xsd and out.wsdl.
The .jar contains a class 'MeldingType', package-info, and schema.xsd
WAR FILE
Package info:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://schemas.xxx.nl/schema/out/v0010", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package nl.xxx.out.web.model;
RequestType
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "XbOutRequestType", propOrder = {
"kenmerk",
"meldingen"
})
public class XbOutRequestType {
#XmlElement(required = true)
protected String kenmerk;
#XmlElement(required = true)
protected List<MeldingType> meldingen = new ArrayList<MeldingType>();
public String getKenmerk() {
return this.kenmerk;
}
public List<MeldingType> getMeldingen() {
return this.meldingen;
}
}
out.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ref="http://schemas.xxx.nl/schema/v0010"
targetNamespace="http://schemas.xxx.nl/out/v0010"
xmlns="http://schemas.xxx.nl/out/v0010"
elementFormDefault="qualified">
<xsd:element name="request" type="RequestType"/>
<xsd:element name="respomse" type="ResponseType"/>
<xsd:complexType name="RequestType">
<xsd:sequence>
<xsd:element name="kenmerk" type="ref:kenmerkType" minOccurs="1"/>
<xsd:element name="meldingen" type="ref:MeldingType" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="XbOutResponseType"/>
</xsd:schema>
out.wsdl
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://schemas.xxx.nl/wsdl/out/v0010"
xmlns:typ="http://schemas.xxx.nl/schema/out/v0010"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="XbRender" targetNamespace="http://schemas.xxx.nl/wsdl/out/v0010">
<wsdl:types>
<xsd:schema targetNamespace="http://schemas.xxx.nl/wsdl/out/v0010" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://schemas.xxx.nl/schema/out/v0010" schemaLocation="out.xsd" />
</xsd:schema>
</wsdl:types>
<wsdl:message name="request">
<wsdl:part name="body" element="typ:request" />
</wsdl:message>
<wsdl:message name="response">
<wsdl:part name="body" element="typ:response" />
</wsdl:message>
<wsdl:portType name="portType">
<wsdl:operation name="execute">
<wsdl:input message="tns:request" />
<wsdl:output message="tns:response" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="soapBinding" type="tns:portType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="execute">
<soap:operation soapAction="execute"/>
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="service">
<wsdl:port binding="tns:soapBinding" name="soapBinding">
<soap:address location="http://localhost:9080/dummy" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
JAR
Package info:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://schemas.xxx.nl/schema/v0010")
package nl.xxx.schema.jaxb.model;
MeldingType
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MeldingType", propOrder = {
"code",
"melding"
})
public class MeldingType {
#XmlElement(required = true)
private String code;
#XmlElement(required = true)
private String melding;
public MeldingType() {
}
public MeldingType(final String code, final String melding) {
this.code = code;
this.melding = melding;
}
public String getCode() {
return this.code;
}
public String getMelding() {
return this.melding;
}
public void setCode(final String code) {
this.code = code;
}
public void setMelding(final String melding) {
this.melding = melding;
}
}
schema.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schemas.xxx.nl/schema/v0010"
xmlns="http://schemas.xxx.nl/schema/v0010"
elementFormDefault="qualified">
<xsd:simpleType name="kenmerkType">
<xsd:restriction base="xsd:string">
<xsd:minLength value="12" />
<xsd:maxLength value="32" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="MeldingType">
<xsd:sequence>
<xsd:element name="code" type="xsd:string" minOccurs="1" />
<xsd:element name="melding" type="xsd:string" minOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

JAX-WS web-service defined by WSDL with abstract global elements

Here is a WSDL containing abstract global element named paramName:
<wsdl:definitions name="AdapterSessionManagerService" targetNamespace="http://companyname.org/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://companyname.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://companyname.org/" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<import namespace="http://companyname.org/adapter1/" schemaLocation="http://localhost:8081/adapters/AdapterSessionManager?xsd=adapter1/ElementName.xsd"/>
<import namespace="http://companyname.org/adapter2/" schemaLocation="http://localhost:8081/adapters/AdapterSessionManager?xsd=adapter2/ElementName.xsd"/>
<xs:element name="initAdapterSession" type="tns:initAdapterSession"/>
<xs:element name="initAdapterSessionResponse" type="tns:initAdapterSessionResponse"/>
<xs:complexType name="initAdapterSession">
<xs:sequence>
<xs:element name="adapterId" type="xs:long"/>
<xs:element name="callbackURL" type="xs:anyURI"/>
<xs:element name="adapterInputData" type="tns:AdapterInputDataType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="initAdapterSessionResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="xs:long"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AdapterInputDataType">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="atomicParam" type="tns:AtomicParamType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AtomicParamType">
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="1" ref="tns:paramName"/>
<xs:element maxOccurs="1" minOccurs="1" name="paramValue" type="tns:AtomicParamValueType"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="AtomicParamValueType">
<xs:union memberTypes="xs:string xs:long xs:decimal xs:dateTime xs:boolean"/>
</xs:simpleType>
<xs:element abstract="true" name="paramName" type="xs:string"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="initAdapterSessionResponse">
<wsdl:part element="tns:initAdapterSessionResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="initAdapterSession">
<wsdl:part element="tns:initAdapterSession" name="parameters"/>
</wsdl:message>
<wsdl:portType name="AdapterSessionManager">
<wsdl:operation name="initAdapterSession">
<wsdl:input message="tns:initAdapterSession" name="initAdapterSession"/>
<wsdl:output message="tns:initAdapterSessionResponse" name="initAdapterSessionResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="AdapterSessionManagerServiceSoapBinding" type="tns:AdapterSessionManager">
<soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="initAdapterSession">
<soap12:operation soapAction="" style="document"/>
<wsdl:input name="initAdapterSession">
<soap12:body use="literal"/>
</wsdl:input>
<wsdl:output name="initAdapterSessionResponse">
<soap12:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="AdapterSessionManagerService">
<wsdl:port binding="tns:AdapterSessionManagerServiceSoapBinding" name="AdapterSessionManagerPort">
<soap12:address location="http://localhost:8081/adapters/AdapterSessionManager"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
This element is intended to be subsituted in SOAP messages with same named elements defined in another namespaces. Here is an example of such definition:
<schema targetNamespace="http://companyname.org/adapter1/" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:inptypns="http://companyname.org/" xmlns:tns="http://companyname.org/adapter1/">
<import namespace="http://companyname.org/"/>
<element name="paramName" substitutionGroup="inptypns:paramName" type="tns:AtomicParamNameType"/>
<simpleType name="AtomicParamNameType">
<restriction base="string">
<enumeration value="foo"/>
<enumeration value="bar"/>
</restriction>
</simpleType>
</schema>
Here is Java code implementing this web-service including code generated by wsimport:
#WebService(wsdlLocation = "WEB-INF/wsdl/AdapterSessionManager.wsdl")
#BindingType(SOAPBinding.SOAP12HTTP_BINDING)
public class AdapterSessionManager {
#WebMethod
public Long initAdapterSession(
#WebParam(name = "adapterId")
#XmlElement(required = true)
Long adapterId,
#WebParam(name = "callbackURL")
#XmlElement(required = true)
URL callbackURL,
#WebParam
#XmlElement(required = true)
AdapterInputDataType adapterInputData
) {...}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AdapterInputDataType", propOrder = {
"atomicParam"
})
public class AdapterInputDataType {
protected List<AtomicParamType> atomicParam;
public List<AtomicParamType> getAtomicParam() {
if (atomicParam == null) {
atomicParam = new ArrayList<AtomicParamType>();
}
return this.atomicParam;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AtomicParamType", propOrder = {
"paramName",
"paramValue"
})
public class AtomicParamType {
#XmlElementRef(name = "paramName", namespace = "http://companyname.org/", type = JAXBElement.class)
protected JAXBElement<?> paramName;
#XmlElement(required = true)
protected String paramValue;
public JAXBElement<?> getParamName() {
return paramName;
}
public void setParamName(JAXBElement<?> value) {
this.paramName = value;
}
public String getParamValue() {
return paramValue;
}
public void setParamValue(String value) {
this.paramValue = value;
}
}
#XmlRegistry
public class ObjectFactory {
private final static QName _ParamName_QNAME = new QName("http://companyname.org/", "paramName");
public ObjectFactory() {
}
public AtomicParamType createAtomicParamType() {
return new AtomicParamType();
}
public AdapterInputDataType createAdapterInputDataType() {
return new AdapterInputDataType();
}
#XmlElementDecl(namespace = "http://companyname.org/", name = "paramName")
public JAXBElement<String> createParamName(String value) {
return new JAXBElement<String>(_ParamName_QNAME, String.class, null, value);
}
}
#XmlType(name = "AtomicParamNameType", namespace = "http://companyname.org/adapter1/")
#XmlEnum
public enum AtomicParamNameType {
#XmlEnumValue("foo")
FOO("foo"),
#XmlEnumValue("bar")
BAR("bar");
private final String value;
AtomicParamNameType(String v) {
value = v;
}
public String value() {
return value;
}
public static AtomicParamNameType fromValue(String v) {
for (AtomicParamNameType c: AtomicParamNameType.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
#XmlRegistry
public class ObjectFactory {
private final static QName _ParamName_QNAME = new QName("http://companyname.org/adapter1/", "paramName");
public ObjectFactory() {
}
#XmlElementDecl(namespace = "http://companyname.org/adapter1/", name = "paramName", substitutionHeadNamespace = "http://companyname.org/", substitutionHeadName = "paramName")
public JAXBElement<AtomicParamNameType> createParamName(AtomicParamNameType value) {
return new JAXBElement<AtomicParamNameType>(_ParamName_QNAME, AtomicParamNameType.class, null, value);
}
}
I'm testing service with the following SOAP-request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://companyname.org/" xmlns:ans="http://companyname.org/adapter1/">
<soapenv:Header/>
<soapenv:Body>
<ws:initAdapterSession>
<adapterId>123</adapterId>
<callbackURL>http://callback</callbackURL>
<adapterInputData>
<atomicParam>
<ans:paramName>foo</ans:paramName>
<paramValue>hello</paramValue>
</atomicParam>
</adapterInputData>
</ws:initAdapterSession>
</soapenv:Body>
</soapenv:Envelope>
I have the following UnmarshallException when an application server receives the request:
javax.xml.bind.UnmarshalException: unexpected element
(uri:"http://companyname.org/adapter1/", local:"paramName"). Expected
elements are <{http://companyname.org/}paramName>,<{}paramValue>
Looks like JAXB is unaware of paramName substitution defined in http://companyname.org/adapter1/ namespace. But I can't imagine why JAXB behaves in such a way. Where is my mistake? Any ideas?
You already know the answer: http://companyname.org/adapter1 is not the same as http://companyname.org/.
Your generated source explicitly indicates that the paramName element is defined in the http://companyname.org/ namespace with the following line.
#XmlElementRef(name = "paramName", namespace = "http://companyname.org/", type = JAXBElement.class)
protected JAXBElement<?> paramName;
So change the namespace attribute to http://companyname.org/adapter1 to allow JAXB properly unmarshal your payload