Hi guys:

I'm in the midst of revamping some stuff, during which I did some surgery on the way 
RPCProvider dispatches to target methods.  In particular, I added a clause to save 
some time which ignores overloaded methods with FEWER parameters than those we have 
from the XML deserialization.  This lit up a serious bug that had been present in the 
code - namely the fact that if there were no arguments in a given method, that one 
would get called regardless of the argument list we were currently working with from 
the XML.  In other words if you had:

 public int method() { return 5; }
 public void method(int value) { // do something }

And received XML with a single int param, it's just as likely you'd dispatch to the 
first method as the second.

Turns out this bug, which has been sitting there a while, it seems, is the reason that 
the wsdl "clash" test was working.  Once it was fixed, the problems with the clash 
test became apparent.

In particular, test #5 in the SharedName_ServiceTestCase calls what it thinks is the 
method that looks like "void sharedName(int)".  It sends XML that contains a parameter 
that has no xsi:type on it (since it's literal), with an element name of <sharedName>, 
i.e. <sharedName>0</sharedName>.  So the runtime gets this, and since there are 
multiple "sharedName" methods, it can't figure out the types from introspection via 
determineDefaultParams() (in org.apache.axis.message.RPCHandler).  So it looks for a 
type attribute - no luck.  Then it says "hey, does the element QName happen to match a 
type I know about?" and lo and behold it does - only this isn't an int, it's a 
"SharedNameType".  So we merrily attempt to deserialize one of those, even though the 
XML isn't quite right for that (NOTE: we should probably be able to enforce throwing 
faults for missing bean elements).  OK, so now we have our SharedNameType in hand, and 
get to RPCProvider to figure out what method to call.  Well, because of the earlier 
bug I mentioned, we find the method that looks like "int sharedName()", and since it 
has no params we just call it and happily return.

That's what WAS happening.  Now the test breaks in my sandbox because we're NOT 
calling the wrong backend method.

So how do we deal with this?  It's a little hard to pinpoint the exact problem(s), so 
let's tease it apart:

1) When lacking an xsi:type attribute, we don't know how to deserialize a given piece 
of XML if there are multiple potential types.  Right now there's an assumption that 
deserialization is done when we get to the RPCProvider, and we just try 
JavaUtils.convert() to coerce whatever we have into whatever we might want.  I think 
the right solution to this might be to keep track of the fact that there are 
overloaded methods during deserialization.  Pick a random method to use as "starter" 
metadata, and if one of the deserializations fails, we should back up, click the 
method counter forward, and try deserializing the XML again as the next type.

2) We should remove the "use the element QName as the type" code, I think it might be 
bogus except for particular elements like <SOAP-ENC:int>.  It's not a generally good 
thing.

3) We need to be able to differentiate between overloaded methods where you can't 
dispatch based on the XML (i.e. "void method(int)" and "void method(String)" where 
there's a single <arg>5</arg>).  Most other toolkits seem to do this with SOAPAction, 
which we could do also.  We could also have a SOAP header based solution.

4) The clash test should be given a thorough once-over.  .NET's wsdl tool chokes on 
it, and I'm not convinced it's really good WSDL testing what we want to test.

I have to go for the evening, but I'll take a look at this again tomorrow.  Russell, 
if you can spare some time I would really appreciate some help going over the test to 
figure out what its doing right and wrong, because I'd like to check my changes in at 
some point during the day tomorrow.

Comments/opinions welcome.

Thanks,
--Glen

Reply via email to