Skip to main content
June 20, 2013
Question

Does cf10 change the way deserializejson handles null?

  • June 20, 2013
  • 3 replies
  • 3961 views

<cftry>

<cfset jsontxt="{""A"":""Bob"",""B"":123,""C"":null}">

<cfset json=deserializejson(jsontxt)>

<cfdump var="#json#">

<cfoutput>

    <li>[#structkeylist(json)#]<br>

    <li>[#json.a#]<br>

    <li>[#json.b#]<br>

    <li>[#json.c#]<br>

</cfoutput>

<cfcatch type="Any">

    <cfdump var="#cfcatch#">

</cfcatch>

</cftry>

The documentation states: The JSON null value becomes the string null.

http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-79e4.html

The above test on CF9 operates as described in the docs, but CF10 errors on #json.c#

I found some old code (compacted a bit), which implies that the old behavior was to convert json's null to "null".

<cfloop list="#structkeylist(contact)#" index="lp">

  <cfset x=evaluate("contact.#lp#")>

  <cfif x eq "null">

    <cfset "contact.#lp#"="">

  </cfif>

</cfloop>

This was just tested on CF10, developer edition, update 10, on Win 2008 x64 and CF9 (9.01) standard

In the meantime, I've added the following just after the deserializejson() command

<cfloop list="#structkeylist(json)#" index="lp">

    <cfparam name="json.#lp#" default="null">

</cfloop>

Is there another way to test for this value? Any array or structure command of some kind?

--Jason Miller

jmiller@quickcert.com

    This topic has been closed for replies.

    3 replies

    Participant
    April 21, 2014

    Here's my function that will perform a DeserializeJSON just as it would have in CF9. For those that REALLY want that behavior back...

    <cfdump var="#DeserializeJSONString(jsonString)#">

    <cffunction name="DeserializeJSONString">

              <cfargument name="stc" required="yes">

              <cfif NOT isStruct(arguments.stc) and isJson(arguments.stc)>

                        <cfset arguments.stc = DeserializeJSON(arguments.stc)>

              </cfif>

              <cfset local.stc = {}>

              <cfloop collection="#arguments.stc#" item="local.n">

                        <cfif isStruct(arguments.stc[local.n])>

                                  <cfset local.stc[local.n] = DeserializeJSONString(arguments.stc[local.n])>

                        <cfelseif isArray(arguments.stc[local.n])>

                                  <cfset local.stc[local.n] = arguments.stc[local.n]>

                                  <cfloop from="1" to="#ArrayLen(local.stc[local.n])#" index="local.i">

                                            <cfparam name="local.stc[local.n][local.i]" default="null">

                                            <cfif isStruct(local.stc[local.n][local.i])>

                                                 <cfset local.stc[local.n][local.i] = DeserializeJSONString(local.stc[local.n][local.i])>

                                            </cfif>

                                  </cfloop>

                        <cfelse>

                                  <cfset local.stc[local.n] = arguments.stc[local.n]>

                                  <cfparam name="local.stc[local.n]" default="null">

                        </cfif>

              </cfloop>

              <cfreturn local.stc>

    </cffunction>

    Inspiring
    June 26, 2013

    Yes, there was a change in behaviour. The CF8 and CF9 behaviour was a bug; CF10 fixes the bug. A NULL value is not the same as a string containing "null", and there never should have been this handling of NULL values because it's brain-numbingly stupid. CF10 fixes this by treating NULL as... well NULL. NULL is a concept CF has traditionally struggled with, but for once in CF10 they're doing it correctly.

    It seems the docs have not caught up: the CF10 docs still describe the buggy behaviour from the previous versions.

    CF10 behaviour is correct. The behaviour in previous versions was incorrect.

    --

    Adam

    JeffryHouser
    Participating Frequently
    June 26, 2013

    Adam,

    Do you have any suggestions on how to deal with this behavior in code? 

    In my version of the world:

      If a structure has a key; then I should not get an "undefined" runtime error trying to access that key's value. 

      I tried to use "isDefined()" but not nowhere.  I am unaware of any "undefined" constants or functions. 

    There is an isNull() function in CF, right?  Has anyone tried that?  I haven't. 

    The structKeyExists() function worked for me; but it feels weird.  If I look over all the structKeys, then the key shows up; but if I use structKeyExists then 'false' is returned.  Something is inconsistent. 

      In this case; I think I'd prefer CF does what they do w/ Database nulls and turn it into an empty string. 

    Inspiring
    June 26, 2013

    Oh, yeah, CF's handling of null values has always been crap, but this is hardly new. What you are describing here is how CF has always behaved.

    There is an isNull() function now, and as far as I have experimented (not much), it does work.

    CF's treatment of NULLs in the context of struct keys / values / struct functions etc is unfortunately not very logical or intuitive.

    You might get a key showing up in a structkeyList() / structKeyArray() / dump of the arguments scope etc, but this doesn't mean it has a value. You need to use structKeyExists() to check for a value. This usage of structKEYExists() is illogical but it's the way CFML works. The function one uses to check if a value is null ought to be structVALUEExists() (or structVALUEIsNull() or something), but the guys who wrote CFML seem to have a tenuous a grasp on how all this should work too.

    --

    Adam

    JeffryHouser
    Participating Frequently
    June 26, 2013

    I ran into the same problem. I fixed it by doing, conceptually, this:

    <cfif structKeyExists(deserializedJSON, key)>

    <cfset realValue = deserializedJSON[key]/>

    <cfelse>

    <!--- process as null value --->

    <cfset realValue = "null"/>

    </cfif>

    Of course, everytime you try to access a value that may be 'null' and is therefore now 'undefined' you have to perform a check like this.  I'm lucky in that I only had to make the change in one spot.  Your approach might be easier. 

    Also, there is a bug for this.

    Inspiring
    June 26, 2013

    JeffryHouser wrote:

    Also, there is a bug for this.

    I'd grant you that there's a ticket in the bugbase, but it's not a bug. it's a misunderstanding about how an earlier bug was fixed.

    --

    Adam