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

936,206

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 &#4E;&#75;&#6C;&#6C;

Share:
936,206
bill
Author by

bill

works on web apps for University of Utah

Updated on July 08, 2022

Comments

  • bill
    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:

    • 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.

    • JensG
      JensG about 10 years
      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
    • Admin
      Admin almost 8 years
      I have a feeling it involves Dave Null.
    • SDsolar
      SDsolar about 7 years
      At least it doesn't involve Chuck Norris. Here's why to stay away from him in code: codesqueeze.com/…
    • Tatranskymedved
      Tatranskymedved about 7 years
      Has the employee considered to change his name?
    • biziclop
      biziclop over 6 years
      Referenced on BBC: bbc.com/future/story/…
    • Antonio Alvarez
      Antonio Alvarez over 5 years
      He should really consider buying a Pointer dog and calling him NullPointer.
    • Lynn Crumbling
      Lynn Crumbling over 4 years
      This employee has got to be a distant relative of Little Bobby Tables.
  • gb.
    gb. almost 11 years
    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.
  • Ben Burns
    Ben Burns almost 11 years
    CDATA was added to the XML spec to avoid these types of kludges.
  • Ben Burns
    Ben Burns almost 11 years
    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".
  • Prashant
    Prashant over 10 years
    name="Null" is of course usefull, and I dont see how it should be related to NaN.
  • bobpaul
    bobpaul over 10 years
    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.
  • AkshayB
    AkshayB over 10 years
    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?
  • Maxx Daymon
    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
    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
    Ben Burns over 10 years
    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.
  • Ben Burns
    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
    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
    Ben Burns over 10 years
    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.
  • Ben Burns
    Ben Burns over 10 years
    Please don't do this. CDATA was created for use in cases where you need to escape an entire block of text.
  • doogle
    doogle over 10 years
    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?
  • Ben Burns
    Ben Burns over 10 years
    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.
  • Prashant
    Prashant about 9 years
    There is no need to escape "Null" with CDATA, there is no such thing as a null keyword in XML.
  • jasonkarns
    jasonkarns about 9 years
    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.
  • Allison
    Allison about 9 years
    @BenBurns Yeah, but what if I want to name my kid &#78;&#117;&#108;&#108;?
  • Ben Burns
    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
    Mr Lister about 7 years
    @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.
  • flarn2006
    flarn2006 over 2 years
    Why all characters? Wouldn't just one be enough?