How to pass "Null" (a real surname!) to a SOAP web service in ActionScript 3
Solution 1
Tracking it down
At first I thought this was a coercion bug where null
was getting coerced to "null"
and a test of "null" == null
was passing. It's not. I was close, but so very, very wrong. Sorry about that!
I've since done lots of fiddling on wonderfl.net and tracing through the code in mx.rpc.xml.*
. At line 1795 of XMLEncoder
(in the 3.5 source), in setValue
, all of the XMLEncoding boils down to
currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));
which is essentially the same as:
currentChild.appendChild("null");
This code, according to my original fiddle, returns an empty XML element. But why?
Cause
According to commenter Justin Mclean on bug report FLEX-33664, the following is the culprit (see last two tests in my fiddle which verify this):
var thisIsNotNull:XML = <root>null</root>;
if(thisIsNotNull == null){
// always branches here, as (thisIsNotNull == null) strangely returns true
// despite the fact that thisIsNotNull is a valid instance of type XML
}
When currentChild.appendChild
is passed the string "null"
, it first converts it to a root XML element with text null
, and then tests that element against the null literal. This is a weak equality test, so either the XML containing null is coerced to the null type, or the null type is coerced to a root xml element containing the string "null", and the test passes where it arguably should fail. One fix might be to always use strict equality tests when checking XML (or anything, really) for "nullness."
Solution
The only reasonable workaround I can think of, short of fixing this bug in every damn version of ActionScript, is to test fields for "null" and escape them as CDATA values.CDATA values are the most appropriate way to mutate an entire text value that would otherwise cause encoding/decoding problems. Hex encoding, for instance, is meant for individual characters. CDATA values are preferred when you're escaping the entire text of an element. The biggest reason for this is that it maintains human readability.
Solution 2
On the xkcd note, the Bobby Tables website has good advice for avoiding the improper interpretation of user data (in this case, the string "Null") in SQL queries in various languages, including ColdFusion.
It is not clear from the question that this is the source of the problem, and given the solution noted in a comment to the first answer (embedding the parameters in a structure) it seems likely that it was something else.
Solution 3
The problem could be in Flex's SOAP encoder. Try extending the SOAP encoder in your Flex application and debug the program to see how the null value is handled.
My guess is, it's passed as NaN (Not a Number). This will mess up the SOAP message unmarshalling process sometime (most notably in the JBoss 5 server...). I remember extending the SOAP encoder and performing an explicit check on how NaN is handled.
Solution 4
@doc_180 had the right concept, except he is focused on numbers, whereas the original poster had issues with strings.
The solution is to change the mx.rpc.xml.XMLEncoder
file. This is line 121:
if (content != null)
result += content;
(I looked at Flex 4.5.1 SDK; line numbers may differ in other versions.)
Basically, the validation fails because 'content is null' and therefore your argument is not added to the outgoing SOAP Packet; thus causing the missing parameter error.
You have to extend this class to remove the validation. Then there is a big snowball up the chain, modifying SOAPEncoder to use your modified XMLEncoder, and then modifying Operation to use your modified SOAPEncoder, and then moidfying WebService to use your alternate Operation class.
I spent a few hours on it, but I need to move on. It'll probably take a day or two.
You may be able to just fix the XMLEncoder line and do some monkey patching to use your own class.
I'll also add that if you switch to using RemoteObject/AMF with ColdFusion, the null is passed without problems.
11/16/2013 update:
I have one more recent addition to my last comment about RemoteObject/AMF. If you are using ColdFusion 10; then properties with a null value on an object are removed from the server-side object. So, you have to check for the properties existence before accessing it or you will get a runtime error.
Check like this:
<cfif (structKeyExists(arguments.myObject,'propertyName')>
<!--- no property code --->
<cfelse>
<!--- handle property normally --->
</cfif>
This is a change in behavior from ColdFusion 9; where the null properties would turn into empty strings.
Edit 12/6/2013
Since there was a question about how nulls are treated, here is a quick sample application to demonstrate how a string "null" will relate to the reserved word null.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="application1_initializeHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function application1_initializeHandler(event:FlexEvent):void
{
var s :String = "null";
if(s != null){
trace('null string is not equal to null reserved word using the != condition');
} else {
trace('null string is equal to null reserved word using the != condition');
}
if(s == null){
trace('null string is equal to null reserved word using the == condition');
} else {
trace('null string is not equal to null reserved word using the == condition');
}
if(s === null){
trace('null string is equal to null reserved word using the === condition');
} else {
trace('null string is not equal to null reserved word using the === condition');
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
The trace output is:
null string is not equal to null reserved word using the != condition
null string is not equal to null reserved word using the == condition
null string is not equal to null reserved word using the === condition
Solution 5
Translate all characters into their hex-entity equivalents. In this case, Null
would be converted into E;KC;C;
Comments
-
bill almost 2 years
We have an employee whose surname is Null. Our employee lookup application is killed when that last name is used as the search term (which happens to be quite often now). The error received (thanks Fiddler!) is:
<soapenv:Fault> <faultcode>soapenv:Server.userException</faultcode> <faultstring>coldfusion.xml.rpc.CFCInvocationException: [coldfusion.runtime.MissingArgumentException : The SEARCHSTRING parameter to the getFacultyNames function is required but was not passed in.]</faultstring>
Cute, huh?
The parameter type is
string
.I am using:
Note that the error does not occur when calling the webservice as an object from a ColdFusion page.
-
JensG about 10 yearsIt may not help you that much with the specific problem, but SOAP 1.2 allows for nullable values, see w3.org/TR/2001/WD-soap12-20010709/#_Toc478383513
-
Admin almost 8 yearsI have a feeling it involves Dave Null.
-
SDsolar about 7 yearsAt least it doesn't involve Chuck Norris. Here's why to stay away from him in code: codesqueeze.com/…
-
Tatranskymedved about 7 yearsHas the employee considered to change his name?
-
biziclop over 6 yearsReferenced on BBC: bbc.com/future/story/…
-
Antonio Alvarez over 5 yearsHe should really consider buying a Pointer dog and calling him NullPointer.
-
Lynn Crumbling over 4 yearsThis employee has got to be a distant relative of Little Bobby Tables.
-
-
gb. almost 11 yearsXXNULLXX could be a name too. You don't know. Maybe people in Indonesia do not have surname and use a variant of XXX as their surname when required.
-
Ben Burns almost 11 yearsCDATA was added to the XML spec to avoid these types of kludges.
-
Ben Burns almost 11 yearsThere's good info here, so I won't downvote, but I figured it's worth a comment. By default, XMLEncoder.as will actually encode a true
null
value properly, by settingxsi:nil="true"
on the element. The issue actually appears to be in the way the ActionScriptXML
type itself (not the encoder) handles the string"null"
. -
Prashant over 10 yearsname="Null" is of course usefull, and I dont see how it should be related to NaN.
-
bobpaul over 10 yearsSame concept, but update all the names in the database and preface then with some character (1Null, 1Smith). Strip off that character in the client. Of course this might be mite work than Reboog's solution.
-
AkshayB over 10 yearsYes, there are a number of possibilities here which will require more debugging to narrow down. 1) Is the WSDL used here expressive enough to distinguish between "NULL" as a string value and an actual null (or omitted) value? 2) If so, is the client encoding the last name correctly (as a string and not a null literal) 3) If so, is the service properly interpreting "NULL" as a string, or coercing it to a null value?
-
Maxx Daymon over 10 years@Reboog711 The employee's last name is literally the string "Null" as in, "My name is Pat Null" Your answer fails to pass the employee's last name. You answer just hides the fact that "Null" is being inappropriately coerced into the language concept of null by the appendChild() method as described by Ben Burns. The result is still failure of the system to deal with Mr. or Ms. Null.
-
JeffryHouser over 10 years@MaxxDaymon I think you misconstrue what my answer actually is. It doesn't present a solution; but rather an explanation of why the problem occurs; and quotes relevant code from the Flex Framework. My more recent edit is perhaps misplaced; as it discusses an alternate approach and is not directly related to the original question.
-
Ben Burns over 10 yearsYou're sort of on the right track, but at that point in the code
content
is the string"null"
, and "null" == null returns false, so that test behaves as intended. Instead I believe the problem is a mix of how XML.appendChild handles a string argument, and how a root XML element containing only the string "null" can be coerced to a literalnull
. -
Ben Burns over 10 years@Reboog711 Take a look at my fiddle. "null" != null` returning
true
is desired behavior here. If the opposite happened, this would discard the string "null" from the encoding process, which in fact would be the cause of the problem. However because this test succeeds, the encoder keeps going, until XML.appendChild discards it due to a coercion bug. -
JeffryHouser over 10 years@BenBurns Forget my previous comments which I just deleted. You're right. It has been a while since I put together a sample to try to help diagnose this and I distinctly remember stepping through that explicit line of code and getting the results I documented in the answer. As to why that is; I'm unclear now. I did leave my "code sample" demonstrating how a null string compares to the null reserved word which is exactly as you said it should.
-
Ben Burns over 10 yearsNo worries. If you want to see the real problem add
var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s);
to your code sample. -
Ben Burns over 10 yearsPlease don't do this. CDATA was created for use in cases where you need to escape an entire block of text.
-
doogle over 10 yearsI could be wrong, but I don't think downvoting just because it wasn't your solution is how it's supposed to work. Also you have to keep in mind the problem calls for a heuristic solution since there isn't one obvious way, as made evident by the variety of solutions posted. Lastly, keeping in mind I don't know CF, wouldn't a decoder just equate the inner text of <message><![CDATA[NULL]]></message> to the inner text of <message>NULL</message>? If so, then is CDATA really a solution at all?
-
Ben Burns over 10 yearsI downvoted because this is an anti-pattern. The bug in this case isn't in CF, it's in ActionScript. However, you raise a good point nonetheless. I'll add a test to my fiddle for CDATA encoding.
-
Prashant about 9 yearsThere is no need to escape "Null" with CDATA, there is no such thing as a null keyword in XML.
-
jasonkarns about 9 yearsAgree with @eckes. I don't understand why there is all this talk of CDATA. CDATA is only useful to escape characters that have special meaning in XML. none of:
n
,u
,l
have special semantics in XML. "NULL" and "<![CDATA[NULL]]>" are identical to an XML parser. -
Allison about 9 years@BenBurns Yeah, but what if I want to name my kid
Null
? -
Ben Burns almost 9 years@jasonkarns - I agree 100% that there should be nothing special about the string/text node
NULL
, but to be pedantic,<blah>null</blah>
and<blah><![CDATA[null]]>
are not the same to an XML parser. They should produce the same results, however the logic flow for handling them is different. It is this effect that we're exploiting as a workaround to the bug in the flex XML implementation. I advocate for this over other approaches as it preserves the readability of the text, and has no side effects for other parsers. -
Mr Lister about 7 years@Sirens That is not the problem. If my name is "<">", then I expect it to be properly escaped as "<&quot;>", that goes without saying. The real problem is with an application behaving as if it uses a blacklist for names.
-
flarn2006 over 2 yearsWhy all characters? Wouldn't just one be enough?