ColdFusion AMF Serialiser inserts ‘null’ values into a cyclic Object graph… what the?

When writing the Flex <=> Transfer integration, coming across a cyclic object graph is pretty common, as onetomany
compositions generate a bi-directional relationship between 2 objects. 
I.e. A Parent knows about its children, and children know about their
parents.

It is also quite possible for situations to occur, where Object A knows
about B, B knows about C, and C knows about A, and therefore having a
complete circle.

What confused me no end pretty much all day yesterday, is that when
trying to send such an Object data structure up to Flex, theAMF Serialiser, doesn't send it up correctly, instead, it decides to replace one Object value with 'null', in an attempt to break the circle.

To give you an example, I set up a CFC, which had a UUID for identity, and a reference to a child (download the code below to have a look), and an appropriate VO on the Flex side.

I then sent this to Flex, as a cyclic graph of objects, like so:


<cfcomponent output="false">
    <cffunction name="getRecursive" hint="returns a circular CFC structure" access="remote" returntype="flexrecursive.Recursive" output="false">
        <cfscript>
            var a = createObject("component", "flexrecursive.Recursive");
            var b = createObject("component", "flexrecursive.Recursive");
            var c = createObject("component", "flexrecursive.Recursive");

            a.setChild(b);
            b.setChild(c);
            c.setChild(a);

            return a;
        </cfscript>
    </cffunction>
</cfcomponent>


So, like above, A knows about B, B knows about C, and C knows about A.

I then passed this up to Flex, and logged whether or not the children in the collection of Objects was null.

In theory, I should be able to run the following code quite happily, without fear of a NullPointerException:


//rec is the returned objects to Flex
trace(rec.id);
trace(rec.child.id);
trace(rec.child.child.id);
//this should output the same id as the 1st line, as they are the the same object
trace(rec.child.child.child.id);


But what happens when I run my test code is:


* retrieved recursive CFCs, should be 3 items in a recursive graph:
rec.id:
id: F47E1371-C2A7-D498-1F6497AA3F3AEBC8
rec.child.id:
id: F47E1375-A404-D99C-50675EB12C98F9B9
rec.child.child.id:
id: F47E1378-A4AA-57E4-192C2A59D73A9832
rec.child.child.child.id:
This child is null!!!


The Serialiser simply replaces 'null' for the last place in the graph, rather than having a reference to the first Object!

I've run this code through Charles, and have confirmed this is also the structure CF sends in AMF as well.

Looking at the AMF Specification, I read:

'Objects can be sent as a reference to a previously occurring Object by using an index to
the implicit object reference table. Further more, trait information can also be sent as a
reference to a previously occurring set of traits by using an index to the implicit traits
reference table.'

So it should be possibly to handle a cyclic graph of objects, as
you could simply insert a reference to a previously serialised
object… so what gives ColdFusion? How come this weird and wacky
behaviour?

This test was run with ColdFusion 8.01, and Flex 3.2.

If you wish to download my CF and Flex test bed, you can from here.

Leave a Comment

Comments

  • Joao Fernandes | December 1, 2008

    Adobe is aware of the issue and I hope they will fix it before the launch of Centaur.