I seem to have uncovered an issue when trying to
deserialize a string array in a complex type.
I'm using axis 1.1, and it receives a request from a
wasp client. The string array in the complex type
is interpreted by axis as a string, rather than an
array, because the xsi:type="SE:Array" attribute is
missing
from the arrayType.
The xml that axis is trying to deserialize looks
something like this:
<AMethod
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SE="http://schemas.xmlsoap.org/soap/encoding/"
<options SE:arrayType="rci0:option[1]"
<item xsi:type="rci0:optionStringArray"
<rci0:name
xsi:type="rci0:optionEnum"someOption</rci0:name
<rci0:value SE:arrayType="xsd:string[1]"
<item
xsi:type="xsd:string"someOptionHere</item
</rci0:value
</item
</options
</rci0:AMethod
Axis throws this exception:
org.xml.sax.SAXException: SimpleDeserializer
encountered a child element, which is NOT expected,
in
something it was trying to deserialize.
at
org.apache.axis.encoding.ser.SimpleDeserializer.onStartChild(SimpleDeserializer.java:189)
at
org.apache.axis.encoding.DeserializationContextImpl.startElement(DeserializationContextImpl.java:1036)
at
org.apache.axis.message.SAX2EventRecorder.replay(SAX2EventRecorder.java:198)
at
org.apache.axis.message.MessageElement.publishToHandler(MessageElement.java:845)
at
org.apache.axis.encoding.DeserializerImpl.startElement(DeserializerImpl.java:409)
at
org.apache.axis.encoding.DeserializationContextImpl.startElement(DeserializationContextImpl.java:1049)
at
org.apache.axis.message.SAX2EventRecorder.replay(SAX2EventRecorder.java:198)
at
org.apache.axis.message.MessageElement.publishToHandler(MessageElement.java:845)
at
org.apache.axis.encoding.DeserializerImpl.startElement(DeserializerImpl.java:409)
at
org.apache.axis.encoding.ser.BeanDeserializer.startElement(BeanDeserializer.java:165)
at
org.apache.axis.encoding.DeserializationContextImpl.startElement(DeserializationContextImpl.java:1049)
at
org.apache.axis.message.SAX2EventRecorder.replay(SAX2EventRecorder.java:198)
at
org.apache.axis.message.MessageElement.publishToHandler(MessageElement.java:845)
at
org.apache.axis.message.RPCElement.deserialize(RPCElement.java:325)
at
org.apache.axis.message.RPCElement.getParams(RPCElement.java:349)
If this line in the xml:
<rci0:value SE:arrayType="xsd:string[1]"
is changed to:
<rci0:value xsi:type="SE:Array"
SE:arrayType="xsd:string[1]"
then axis is fine.
However, I looked at section 5.1 of the SOAP 1.1
spec, and it seems to me that axis should be able to
determine that the value element is a string array
(i.e. the xsi:type is optional when the arrayType
attribute exists).
I dropped this in a debugger to verify that it was
the string array that was producing the exception.
From looking at the code in axis from Nov. 17, the
BeanDeserializer class needs a 1 line change to fix
this issue:
On line 266, change :
QName childXMLType =
context.getTypeFromXSITypeAttr(namespace,
to:
QName childXMLType =
context.getTypeFromAttributes(namespace,
The getTypeFromXSIType method isn't used anywhere
else
in the code (except within the getTypeFromAttributes
method).
I've attached some modified versions of an axis test
("testTravelRequest") to demonstrate the problem.
Is this a bug? And is the patch reasonable?
___TestBeanDeser2.java _______________________________
package test.encoding;
import junit.framework.TestCase;
import org.apache.axis.Constants;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.encoding.TypeMapping;
import org.apache.axis.encoding.TypeMappingRegistry;
import org.apache.axis.message.RPCElement;
import org.apache.axis.message.RPCParam;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.server.AxisServer;
import javax.xml.namespace.QName;
import java.util.Vector;
/**
* Test deserialization of SOAP responses
*/
public class TestBeanDeser2 extends TestCase {
private String header;
private String footer;
private AxisServer server = new AxisServer();
public TestBeanDeser2(String name) {
super(name);
header =
"<?xml version=\"1.0\"
encoding=\"UTF-8\"?\n" +
"<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"
+
"
xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
+
"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+
"
xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"
+
"<SOAP-ENV:Body\n";
footer =
"</SOAP-ENV:Body\n"+
"</SOAP-ENV:Envelope\n";
TypeMappingRegistry tmr =
server.getTypeMappingRegistry();
TypeMapping tm = (TypeMapping)
tmr.createTypeMapping();
tm.setSupportedEncodings(new
String[]{Constants.URI_DEFAULT_SOAP_ENC});
tmr.register(Constants.URI_DEFAULT_SOAP_ENC,
tm);
tm.register(test.encoding.beans.SbTravelRequest.class,
new
QName("http://www.sidestep.com/sbws",
"SbTravelRequest"),
new
org.apache.axis.encoding.ser.BeanSerializerFactory(
test.encoding.beans.SbTravelRequest.class,
new
QName("http://www.sidestep.com/sbws",
"SbTravelRequest")),
new
org.apache.axis.encoding.ser.BeanDeserializerFactory(
test.encoding.beans.SbTravelRequest.class,
new
QName("http://www.sidestep.com/sbws",
"SbTravelRequest")));
tm.register(test.encoding.beans.SbSupplier.class,
new
QName("http://www.sidestep.com/sbws", "SbSupplier"),
new
org.apache.axis.encoding.ser.BeanSerializerFactory(
test.encoding.beans.SbSupplier.class,
new
QName("http://www.sidestep.com/sbws",
"SbSupplier")),
new
org.apache.axis.encoding.ser.BeanDeserializerFactory(
test.encoding.beans.SbSupplier.class,
new
QName("http://www.sidestep.com/sbws",
"SbSupplier")));
}
protected Object deserialize(String data)
throws Exception {
Message message = new Message(header + data
+ footer);
message.setMessageContext(new
MessageContext(server));
SOAPEnvelope envelope = (SOAPEnvelope)
message.getSOAPEnvelope();
assertNotNull("SOAP envelope should not be
null", envelope);
RPCElement body = (RPCElement)
envelope.getFirstBody();
assertNotNull("SOAP body should not be
null", body);
Vector arglist = body.getParams();
assertNotNull("arglist", arglist);
assertTrue("param.size()<=0 {Should be
0}", arglist.size() 0);
RPCParam param = (RPCParam) arglist.get(0);
assertNotNull("SOAP param should not be
null", param);
return param.getValue();
}
public void testTravelRequest() throws Exception
{
String response =
"<startSearch\n"+
" <arg0 href=\"#id0\"/\n"+
"</startSearch\n"+
"<multiRef id=\"id0\"
SOAP-ENC:root=\"0\"\n"+
"
encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"+
"
xsi:type=\"ns2:SbTravelRequest\"\n"+
"
xmlns:ns1=\"http://schemas.xmlsoap.org/soap/envelope/:encodingStyle\"\n"+
"
xmlns:ns2=\"http://www.sidestep.com/sbws\"\n"+
"<requestOr
xsi:type=\"xsd:string\"SOAP test 1</requestOr\n"+
"<homeCountry
xsi:type=\"xsd:string\"US</homeCountry\n"+
"<departureLocation
xsi:type=\"xsd:string\"SJC</departureLocation\n"+
"<destinationLocation
xsi:type=\"xsd:string\"ATL</destinationLocation\n"+
"<startDate
xsi:type=\"xsd:dateTime\"2002-08-10T13:42:24.024Z</startDate\n"+
"<endDate
xsi:type=\"xsd:dateTime\"2002-06-27T13:42:24.024Z</endDate\n"+
"<searchTypes
xsi:type=\"xsd:string\"AIR:RTACR</searchTypes\n"+
"<searchParams xsi:nil=\"true\"/\n"+
"<searchHints xsi:nil=\"true\"/\n"+
"<supPliers xsi:type=\"SOAP-ENC:Array\"
SOAP-ENC:arrayType=\"ns2:SbSupplier[1]\"\n"+
" <item href=\"#id1\"/\n"+
"</supPliers\n"+
"</multiRef"+
"<multiRef id=\"id1\"
SOAP-ENC:root=\"0\""+
"
encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""+
"
xsi:type=\"ns3:SbSupplier\""+
"
xmlns:ns3=\"http://www.sidestep.com/sbws\""+
" <searchType
xsi:type=\"xsd:int\"0</searchType"+
" <supplierCode
xsi:type=\"xsd:string\"SC**</supplierCode"+
" <chanNel
xsi:type=\"xsd:string\"CN**</chanNel"+
"<listOfStrings " +
"SOAP-ENC:arrayType=\"xsd:string[3]\" " +
"<item xsi:type=\"xsd:string\"abc</item" +
"<item xsi:nil=\"true\"/" +
"<item xsi:type=\"xsd:string\"def</item" +
"</listOfStrings" +
"</multiRef";
test.encoding.beans.SbTravelRequest
travelRequest =
(test.encoding.beans.SbTravelRequest)
deserialize(response);
assertNotNull("supPliers array missing",
travelRequest.supPliers);
assertTrue(travelRequest.supPliers.length==1);
assertTrue(travelRequest.supPliers[0].searchType.intValue()==0);
assertTrue(travelRequest.supPliers[0].supplierCode.equals("SC**"));
assertTrue(travelRequest.supPliers[0].chanNel.equals("CN**"));
}
public static void main(String [] args) throws
Exception
{
TestBeanDeser2 tester = new
TestBeanDeser2("test");
tester.testTravelRequest();
}
}
___sbSupplier.java____________________________________
package test.encoding.beans;
public class SbSupplier implements
java.io.Serializable
{
public SbSupplier(){}
public Integer searchType;
public String supplierCode;
public String chanNel;
public String[] listOfStrings;
}
______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca