How to pass "Null" (a real surname!) to a SOAP web service in ActionScript 3

Created 16.12.2010 00:42
Viewed 929K times
4681 votes

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:

  • WSDL (SOAP)
  • Flex 3.5
  • ActionScript 3
  • ColdFusion 8

Note that the error does not occur when calling the webservice as an object from a ColdFusion page.

7
Comments
It 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 by JensG, 07.04.2014 21:04
I have a feeling it involves Dave Null. by George Gibson, 01.08.2016 11:16
At least it doesn't involve Chuck Norris. Here's why to stay away from him in code: codesqueeze.com/… by SDsolar, 03.06.2017 18:12
Has the employee considered to change his name? by Tatranskymedved, 30.06.2017 06:24
Referenced on BBC: bbc.com/future/story/… by biziclop, 29.12.2017 03:55
He should really consider buying a Pointer dog and calling him NullPointer. by Antonio Alvarez, 22.11.2018 08:09
This employee has got to be a distant relative of Little Bobby Tables. by Lynn Crumbling, 17.02.2020 18:34
Show remaining 2 comments
Answers 9
0
1124

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.

01.08.2013 17:31
1
243

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.

16.01.2011 08:13
Comments
name="Null" is of course usefull, and I dont see how it should be related to NaN. by eckes, 15.11.2013 21:01
0
302

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.

27.04.2012 20:00
6
129

@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

03.05.2012 15:51
Comments
@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. by Maxx Daymon, 21.11.2013 21:19
@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. by JeffryHouser, 21.11.2013 22:01
You'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 literal null. by Ben Burns, 06.12.2013 16:57
@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. by Ben Burns, 06.12.2013 17:19
@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. by JeffryHouser, 06.12.2013 17:21
No 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. by Ben Burns, 06.12.2013 17:28
Show remaining 1 comments
3
65

Translate all characters into their hex-entity equivalents. In this case, Null would be converted into &#4E;&#75;&#6C;&#6C;

30.04.2012 19:03
Comments
Please don't do this. CDATA was created for use in cases where you need to escape an entire block of text. by Ben Burns, 06.12.2013 17:46
I 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? by doogle, 06.12.2013 19:38
I 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. by Ben Burns, 19.12.2013 15:54
4
39

As a hack, you could consider having a special handling on the client side, converting 'Null' string to something that will never occur, for example, XXNULLXX and converting back on the server.

It is not pretty, but it may solve the issue for such a boundary case.

28.04.2012 08:43
Comments
XXNULLXX 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. by gb., 02.08.2013 08:42
Same 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. by bobpaul, 16.11.2013 04:30
@BenBurns Yeah, but what if I want to name my kid &#78;&#117;&#108;&#108;? by Allison, 11.05.2015 23:22
@Sirens That is not the problem. If my name is "<&quot;>", then I expect it to be properly escaped as &quot;&lt;&amp;quot;&gt;&quot;, that goes without saying. The real problem is with an application behaving as if it uses a blacklist for names. by Mr Lister, 17.04.2017 11:04
1
51

Stringifying a null value in ActionScript will give the string "NULL". My suspicion is that someone has decided that it is, therefore, a good idea to decode the string "NULL" as null, causing the breakage you see here -- probably because they were passing in null objects and getting strings in the database, when they didn't want that (so be sure to check for that kind of bug, too).

28.04.2012 20:15
Comments
Yes, 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? by pimlottc, 17.11.2013 21:24
1
30

Well, I guess that Flex' implementation of the SOAP Encoder seems to serialize null values incorrectly. Serializing them as a String Null doesn't seem to be a good solution. The formally correct version seems to be to pass a null value as:

<childtag2 xsi:nil="true" />

So the value of "Null" would be nothing else than a valid string, which is exactly what you are looking for.

I guess getting this fixed in Apache Flex shouldn't be that hard to get done. I would recommend opening a Jira issue or to contact the guys of the apache-flex mailinglist. However this would only fix the client side. I can't say if ColdFusion will be able to work with null values encoded this way.

See also Radu Cotescu's blog post How to send null values in soapUI requests.

17.07.2013 07:56
Comments
There'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 setting xsi:nil="true" on the element. The issue actually appears to be in the way the ActionScript XML type itself (not the encoder) handles the string "null". by Ben Burns, 02.08.2013 14:55
4
21

It's a kludge, but assuming there's a minimum length for SEARCHSTRING, for example 2 characters, substring the SEARCHSTRING parameter at the second character and pass it as two parameters instead: SEARCHSTRING1 ("Nu") and SEARCHSTRING2 ("ll"). Concatenate them back together when executing the query to the database.

28.04.2012 19:48
Comments
CDATA was added to the XML spec to avoid these types of kludges. by Ben Burns, 02.08.2013 14:31
There is no need to escape "Null" with CDATA, there is no such thing as a null keyword in XML. by eckes, 18.04.2015 19:20
Agree 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. by jasonkarns, 18.04.2015 19:46
@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. by Ben Burns, 08.09.2015 07:39