Invalid Element in SOAP Request - java

I auto-generated a solution from a WSDL file for a project I'm working on, but for some reason the solution does not seem to correctly handle the input specified by the WSDL. Does anyone know what I can do to fix it?
Given the following operation:
<wsdl:operation name="createBin">
<wsdl:input message="impl:createBinRequest" name="createBinRequest"/>
<wsdl:output message="impl:createBinResponse" name="createBinResponse"/>
</wsdl:operation>
<wsdl:message name="createBinRequest">
<wsdl:part element="impl:createBin" name="parameters"/>
</wsdl:message>
<element name="createBin">
<complexType>
<sequence>
<element name="request" type="impl:Bin"/>
</sequence>
</complexType>
</element>
<complexType name="Bin">
<sequence>
<element name="FulfillerID" type="xsd:positiveInteger"/>
<element name="BinID" nillable="true" type="xsd:positiveInteger"/>
<element name="ExternalLocationID" type="xsd:string"/>
<element name="BinType" type="xsd:string"/>
<element name="BinStatus" type="xsd:string"/>
<element name="Name" nillable="true" type="xsd:string"/>
</sequence>
</complexType>
Implemented with this code (auto-generated by eclipse):
public PositiveInteger createBin(Bin request) throws RemoteException {
throw new UnsupportedOperationException();
}
When sending this message:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://my.api.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<q0:createBin>
<q0:request>
<q0:FulfillerID>1234</q0:FulfillerID>
<q0:BinID>1234</q0:BinID>
<q0:ExternalLocationID>1234</q0:ExternalLocationID>
<q0:BinType>Good</q0:BinType>
<q0:BinStatus>Bad</q0:BinStatus>
<q0:Name>Ugly</q0:Name>
</q0:request>
</q0:createBin>
</soapenv:Body>
</soapenv:Envelope>
I get the following error:
<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>
<soapenv:Fault>
<faultcode>soapenv:Server.userException</faultcode>
<faultstring>org.xml.sax.SAXException: Invalid element in com.api.my.Bin - request</faultstring>
<detail>
<ns1:hostname xmlns:ns1="http://xml.apache.org/axis/">localhost</ns1:hostname>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
I'm 100% sure that the SOAP message is the correct format, so my server must be choking on something. When I remove the parameter, everything works swimmingly for some reason.
I can however, get the expected behavior by removing the element like so:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://my.api.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<q0:createBin>
<q0:FulfillerID>1234</q0:FulfillerID>
<q0:BinID>1234</q0:BinID>
<q0:ExternalLocationID>1234</q0:ExternalLocationID>
<q0:BinType>Good</q0:BinType>
<q0:BinStatus>Bad</q0:BinStatus>
<q0:Name>Ugly</q0:Name>
</q0:createBin>
</soapenv:Body>
</soapenv:Envelope>

I'm searching my brain to remember where I saw this before, but I'm certain I've seen some seemingly 'invalid SOAP requests' which turned out to be invalid because the response was invalid.
In this light: could you change the generated createBin(Bin request) code to return a PositiveInteger rather than -3? Maybe if we can make te response valid, your server will stop complaining.
Good Luck!

It turns out the SAX parser is not interpreting the request that it looks like it should. Even though the parameter to the method is request, it ignores that and expects to parse an element that has a request field of type com.api.my.Bin. The problem was fixed by changing .
public PositiveInteger createBin(Bin request) throws RemoteException {
throw new UnsupportedOperationException();
}
With
public PositiveInteger createBin(CreateBin request) throws RemoteException {
throw new UnsupportedOperationException();
}
Where
public class CreateBin {
public Bin request;
/* ... */
}
Though, to be transparent, I did have to do a lot of tweaking to the CoreServiceSoapBindingStub and CoreServiceSoapBindingSkeleton that eclipse generated in order to get the whole thing not to blow up because of invalid something-or-other.

Related

Adapt Axis multiRef WSDL for JAXWS

We have a very old axis web service that we need to use with a client made with jaxws. One of the methods of this web services returns a type apachesoap:Document, where apachesoap schema is http://xml.apache.org/xml-soap.
The response XML looks like this:
<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>
<ns1:consultaXMLResponse xmlns:ns1="http://webservices.imagapp.app" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<consultaXMLReturn href="#id0"/>
</ns1:consultaXMLResponse>
<multiRef xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns2="http://xml.apache.org/xml-soap" id="id0" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:Document">
<DatosConsultaWS>
<Registro>2974161</Registro>
</DatosConsultaWS>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
My adapted wsdl schema looks like this (I show only the response element, the rest I don't think is relevant because works fine).
<element name="consultaXMLResponse">
<complexType>
<sequence>
<element name="consultaXMLReturn">
<complexType>
<sequence>
<element name="DatosConsultaWS">
<complexType>
<sequence>
<element name="Registro" type="xsd:string"/>
</sequence>
</complexType>
</element>
</sequence>
<attribute name="href" type="xsd:anyURI"/>
<attribute name="id" type="xsd:ID"/>
<anyAttribute namespace="##other" processContents="strict"/>
</complexType>
</element>
</sequence>
</complexType>
</element>
However with this element, when I call that method, my client returns null (not even a ConsultaXMLReturn with null value inside).
I don't really know if what I'm trying to do is even posible.
Ideas? thanks.

JAX-WS Client won't accept blank namespace in SOAP Response

I'm trying to pull data from a webservice using JAX-WS and code generated by wsimport. I'm able to send the request and get a response from the server, but JAX-WS is throwing an exception when it tries to read the response because no elements in the response body have a declared namespace.
Exception in thread "main" com.sun.xml.internal.ws.streaming.XMLStreamReaderException: unexpected XML tag. expected: {http://www.theserver.com/cmdb_rel_ci}getRecordsResponse but found: {null}getRecordsResponse
WSDL Excerpt:
<wsdl:definitions xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:tns="http://www.theserver.com/cmdb_rel_ci" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sncns="http://www.theserver.com" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://www.theserver.com">
<wsdl:types>
<xsd:schema elementFormDefault="unqualified" targetNamespace="http://www.theserver.com/cmdb_rel_ci">
<xsd:element name="getRecords">
<xsd:complexType>
<xsd:sequence>
<!-- Request arguments -->
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="getRecordsResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="getRecordsResult">
<xsd:complexType>
<xsd:sequence>
<!-- Response Fields -->
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="getRecordsSoapIn">
<wsdl:part name="cmdb_rel_ci" element="tns:getRecords"></wsdl:part>
</wsdl:message>
<wsdl:message name="getRecordsSoapOut">
<wsdl:part name="cmdb_rel_ci" element="tns:getRecordsResponse"></wsdl:part>
</wsdl:message>
</wsdl:definitions>
Successful Request and Response in SoapUI:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.theserver.com/cmdb_rel_ci">
<soapenv:Header/>
<soapenv:Body>
<ns2:getRecords>
<arg1>value</arg1>
<!-- Remaining Arguments -->
</ns2:getRecords>
</soapenv:Body>
</soapenv:Envelope>
<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>
<resultField1>value</resultField1>
<resultField2>value2</resultField2>
<!-- etc. -->
</getRecordsResult>
<!-- Other getRecordsResult elements -->
</getRecordsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How do I tell JAX-WS that the <getRecordsResponse> element won't have a namespace? I've tried setting targetNamespace = "" in the #ResponseWrapper annotation for getRecords(), but that just makes it expect the targetNamespace parameter from #WebService instead. And when I tried as a last-ditch effort to set the WebService's target namespace blank, it tried to infer a namespace from the Java package name (e.g. "http://my_package.com").
I was unable to find a way to tell JAX-WS not to expect a namespace, but I was able to work around it by pre-processing the response in a SOAPHandler and manually adding a namespace to the XML element (by giving it a new QName that included a namespace declaration).
MyHandler.java:
public class MyHandler implements SOAPHandler<SOAPMessageContext> {
#Override
public void close(MessageContext context) {
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
//Don't intercept outbound messages (SOAP Requests)
if ((Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {return true;}
SOAPMessage message = context.getMessage();
try {
SOAPBody body = message.getSOAPBody();
Iterator<SOAPElement> bodyIterator = body.getChildElements();
SOAPElement responseElement = bodyIterator.next();
responseElement.setElementQName(new QName("http://www.theserver.com/cmdb_rel_ci", origGetRecordsResponse.getLocalName(), "cmdb"));
} catch (Exception e) {e.printStackTrace();}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
#Override
public Set<QName> getHeaders() {
return Collections.emptySet();
}
}
Then I just had to add my Handler to the HandlerChain with the following code in my main class, and it worked.
Binding binding = ((BindingProvider)port).getBinding();
List<Handler> handlers = binding.getHandlerChain();
handlers.add(new MyHandler());
binding.setHandlerChain(handlers);
The question here is
How do I tell JAX-WS that the element won't have a namespace? I've tried setting targetNamespace = "" in the #ResponseWrapper annotation for getRecords(), but that just makes it expect the targetNamespace parameter from #WebService instead.
Answer is here
https://docs.oracle.com/cd/E13222_01/wls/docs92/webserv/annotations.html
TO make sure that targetNamespace is not ignored, change the SOAPBinding style to SOAPBinding.Style.Document
Information from the above url which gives more insights into the issue.
The XML namespace of the return value. This value is used only used for document-style Web Services, in which the return value maps to an XML element.
The default value is the targetNamespace of the Web Service.

How do I convert the following xml into java objects using JAXB

What is the best way to convert this XML into Java objects?
<entity>
<customers id=2 other="data">
<customer name="john">testData1</customer>
<customer name="jenny">testData2</customer>
<customer name="joe">testData3</customer>
<customer name="joanna">testData4</customer>
</customers>
</entity>
Is it best to use a custom XMLAdapter with a HashMap to convert multiple xml rows of <customer>? I'm not sure if the XMLAdapter is the proper use case for this scenario. Any ideas would be appreciated.
Since the nesting isn't very deep, you could just have Entity, Customer classes and then use these annotations for the mapping in the entity class:
#XmlElementWrapper(name="customers")
#XmlElement(name="customer")
public void setCustomers(List<Customer> customers) {
this.customers= customers;
}
References:
XmlElementWrapper
Best approach, in my opinion, would be to write an xsd file to validate against your xml. You can use that to generate your java classes using xjc which comes bundled with Java. This should get you there.
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:NameOfNamespace="http://enter.your.namespace.here"
targetNamespace="http://enter.your.namespace.here"
attributeFormDefault="unqualified"
elementFormDefault="qualified">
<complexType name="customer">
<simpleContent>
<extension base="string">
<attribute name="name"/>
</extension>
</simpleContent>
</complexType>
<complexType name="customers">
<sequence>
<element name="customer" type="NameOfNamespace:customer"/>
</sequence>
<attribute name="id" type="positiveInteger"/>
<attribute name="other"/>
</complexType>
<complexType name="entity" >
<sequence>
<element name="customers" type="NameOfNamespace:customers" minOccurs="1" maxOccurs="1"/>
</sequence>
</complexType>
<element name="entity" type="NameOfNamespace:entity"/>
</schema>
Open a command prompt to the folder where you put your xsd file, and then generate java code you'll just need to type:
$ xjc nameOfSchemaFile.xsd
assuming your java 'bin' folder is in your path. The classes generated will be created in folder with the same name as your targetNamespace.
Using these you can follow the instructions in Naimish's example JAXB Hello World Example

Array of object parameter in Java Webservice Provider

My provider must have an array of object as input parameter, according to the WSDL:
<element name="classifica" type="Q4:Titolario" maxOccurs="unbounded" minOccurs="0"/>
This is the generated method:
public void protoModificaProtocollo(...,...,...,Titolario[] classifica,....) {
How to get the input values of this array (always returns null).
EDIT
This is the xsd schema of the method to provide:
<import schemaLocation="TipoVerso.xsd" namespace="http://regione.toscana.it/rfc205/interpro.TipoVerso"/>
<import schemaLocation="Anagrafica.xsd" namespace="http://regione.toscana.it/rfc205/interpro.Anagrafica"/>
<import schemaLocation="Titolario.xsd" namespace="http://regione.toscana.it/rfc205/interpro.Titolario"/>
<element name="protoModificaProtocolloElement" type="tns:protoModificaProtocollo"/>
<complexType name="protoModificaProtocollo">
<sequence>
<element name="numero" type="int" maxOccurs="1" minOccurs="1"/>
<element name="anno" type="int" maxOccurs="1" minOccurs="1"/>
<element name="verso" type="Q1:TipoVerso" maxOccurs="1" minOccurs="1"/>
<element name="oggetto" type="string" maxOccurs="1" minOccurs="0"/>
<element name="classifica" type="Q4:Titolario" maxOccurs="unbounded" minOccurs="0"/>
<element name="ufficio" type="Q2:Anagrafica" maxOccurs="unbounded" minOccurs="0"/>
</sequence>
</complexType>
and this is the xsd schema of Titolario
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://regione.toscana.it/rfc205/interpro.Titolario"
elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://regione.toscana.it/rfc205/interpro.Titolario">
<complexType name="Titolario">
<sequence>
<element name="codice" type="string" maxOccurs="1" minOccurs="1"></element>
<element name="descrizione" type="string" maxOccurs="1" minOccurs="0">
</element>
</sequence>
</complexType>
</schema>
Here the SOAP message sent:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:int="http://regione.toscana.it/rfc205/interpro"
xmlns:int1="http://regione.toscana.it/rfc205/interpro.protoModificaProtocollo"
xmlns:int2="http://regione.toscana.it/rfc205/interpro.Titolario"
xmlns:int3="http://regione.toscana.it/rfc205/interpro.Anagrafica">
<soapenv:Header/>
<soapenv:Body>
<int:protoModificaProtocollo>
<int1:numero>140</int1:numero>
<int1:anno>2014</int1:anno>
<int1:verso>P</int1:verso>
<!--Optional:-->
<int1:oggetto>test</int1:oggetto>
<!--Zero or more repetitions:-->
<int1:classifica>
<int2:codice>34</int2:codice>
<!--Optional:-->
<int2:descrizione>test description</int2:descrizione>
</int1:classifica>
</int:protoModificaProtocollo>
</soapenv:Body>
</soapenv:Envelope>
In the provider, this is the method:
public void protoModificaProtocollo(int numero, int anno, TipoVerso verso,
String oggetto, Titolario[] classificazione, Anagrafica[] ufficio,
ResponseProtocolloHolder protocollo_resp, ResponseErrorHolder response_msg_err) {
... some stuff here ...
System.out.println("getCodice():" + classificazione[0].getCodice()); <-- THIS LINE ALWAYS RETURNS NULL
Notice that, in input parameters, if I change
Titolario[] classificazione
with
Titolario classificazione
my debug line prints:
34
UPDATE 2
TIA Simon, here pastebin you can find the full WSDL. And here Titolario.java the class for Titolario. I've noticed that when consumer call provider, Titolario constructor i call N times, depending of number of Titolario occurrences in SOAP request. As you can see, the constructor is an empty constructor.
In this moment, my protocol is RPC/encoded, just becouse i've must understand the problem reported here Literal vs Encoded (if you please can take a look also at this...:-))
I've found some references about the problem, for example this article, maybe related to mine.
Anyway, i would like to know if there is a Java workaround to manage this. Thanks again!
Found the problem!
The fact was that i've used the same given WSDL both to generate the provider and to create the SoapUI project.
Basically the trick was:
generate the provider in Domino using the given WSDL
set RPC/Literal, according to the <soap:body use="literal"/> directive
export the Domino WSDL of the provider
create the SoapUI project with it
use it to call services provided
That's it! ... a very stupid mistake! :-(
Without a full WSDL I can't say with 100% this is the issue.
Based on what you have so far.
1. There are known issues where the "xsd:string" is wrapped with custom string handler. I have see references before where "string" would just sit on top of "xsd:string". So I would start with changing that back to "xsd:string" and see if it helps.
2. As your web service provider has the following:
Titolario[] classifica
Normally your WSDL should create an xxxArray Object which your consumer sends, and not the array object itself. (Tested on Doc/Literal + RPC/Literal, as "minoccurs" only shows up on Literal).
For example:
public String TestProtoModificaProtocollo (Titolario x[]) { ...
Converts to:
<complexType name="Titolario">
<sequence>
<element name="codice" nillable="true" type="xsd:string"/>
<element maxOccurs="unbounded" minOccurs="0" name="descrizione" nillable="true" type="xsd:string"/>
</sequence>
</complexType>
<complexType name="TitolarioArray">
<sequence>
<element maxOccurs="unbounded" minOccurs="0" name="item" type="impl:Titolario"/>
</sequence>
</complexType>
<element name="x" type="impl:TitolarioArray"/>
<element name="TestProtoModificaProtocolloReturn" type="xsd:string"/>
So your consumer would translate to:
public java.lang.String testProtoModificaProtocollo(TitolarioArray x) throws java.rmi.RemoteException;

webservice Cannot assign object of type System.Xml.XmlNode[] to an object of type System.String

I am trying to consume a Java Webservice using Visual Basic.net. I am getting an error on deserialization "Cannot assign object of type System.Xml.XmlNode[] to an object of type System.String".
What I have been reading is that the wsdl specification may not conform to the WS-I BP 1.1 specification. Link Here
The other solution talked about here is to change the response xml to conform to a .net datatype. I have tried to do this for other reasons a couple of years back and it proved to be unstable.
A snippet of the wsdl is this:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.interfaces.sessions.APILink.amdocs"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="http://ws.interfaces.sessions.APILink.amdocs"
xmlns:intf="http://ws.interfaces.sessions.APILink.amdocs"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns2="http://io.datainfo.APILink.amdocs"
xmlns:tns3="http://datainfo.APILink.amdocs"
xmlns:tns4="http://awsi.amdocs.com"
xmlns:tns5="http://exceptions.APILink.amdocs"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<complexType name="InPersonInfo">
<complexContent>
<extension base="tns2:BaseInputOutputInfo">
<sequence>
<element maxOccurs="1" minOccurs="0" name="mItem1" type="xsd:int"/>
<element maxOccurs="1" minOccurs="0" name="mID" nillable="true" type="xsd:string"/>
<element maxOccurs="1" minOccurs="0" name="mPersonType" type="tns4:char"/>
</sequence>
</extension>
</complexContent>
</complexType>
The other pieces from the WSDL I am seeing is just the message and operation sections.
EDIT 2011-04-21: This question mentions what I am going through.
I am not familiar with java what I know is that it is being created/consumed with AXIS or SOAPUI and somehow it is not creating the WSDL according to standard and there is my problem. If I find an answer to solve it I will post it here.

Categories

Resources