Skip to main content
Ben Nadel at Scotch On The Rock (SOTR) 2010 (London) with: Dan Lancelot
Ben Nadel at Scotch On The Rock (SOTR) 2010 (London) with: Dan Lancelot

Checking To See If A Struct Is Of Type Ordered / Linked In Lucee CFML 5.3.6.61

By
Published in Comments (2)

One of the really excited features of ColdFusion is that it can create linked / ordered Structs. These are Structs (objects, hashes, maps) in which the key-iteration order matches the order in which the keys were originally defined. As I discussed last year, ordered Structs are perfect for MongoDB interactions, where the order of the key-iteration determines the underlying database interaction behaviors. The other day, I was building a Gateway wrapper to a MongoDB database; and, due to the importance of the Struct implementation, I wanted to see if I could, perhaps, require the MongoDB query documents to be Ordered / Linked Structs. ColdFusion doesn't provide decision functions around Struct type; so, I wanted to see how I might determine if a Struct is of type Ordered / Linked in Lucee CFML 5.3.6.61.

CAUTION: I am using undocumented, implementation details here - but, I am encapsulating them within Function boundaries.

To figure out a plan of attack, I started looking around in the Lucee CFML source code for the StructImpl class. I was hoping that each "type" of Struct was actually a different class; and then, maybe, I could just use the isInstanceOf() ColdFusion function. But, it looks like the StructImpl class just wraps a map of a given Type. That said, it does have a .getType() method, which exposes the Type of said underlying map. So, I ended up using the .getType() method to determine what type of Struct I had:

<cfscript>

	normal = {};
	linked = [:];
	weak = structNew( "weak" );
	// As a test case, let's try a value that isn't a Struct at all.
	none = "hello";

	echo( "<strong> Normal : </strong>" );
	echo( "#isNormalStruct( normal )# , #isLinkedStruct( normal )# , #isWeakStruct( normal )#" );
	echo( "<br />" );

	echo( "<strong> Linked : </strong>" );
	echo( "#isNormalStruct( linked )# , #isLinkedStruct( linked )# , #isWeakStruct( linked )#" );
	echo( "<br />" );

	echo( "<strong> Weak : </strong>" );
	echo( "#isNormalStruct( weak )# , #isLinkedStruct( weak )# , #isWeakStruct( weak )#" );
	echo( "<br />" );

	echo( "<strong> None : </strong>" );
	echo( "#isNormalStruct( none )# , #isLinkedStruct( none )# , #isWeakStruct( none )#" );
	echo( "<br />" );

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	/**
	* I determine if the given value is a "normal" Struct.
	* 
	* @value I am the value being inspected.
	*/
	public boolean function isNormalStruct( required any value ) {

		return(
			isStructOfType( value, "TYPE_UNDEFINED" ) ||
			isStructOfType( value, "TYPE_REGULAR" )
		);

	}


	/**
	* I determine if the given value is a "linked" or "ordered" Struct.
	* 
	* @value I am the value being inspected.
	*/
	public boolean function isLinkedStruct( required any value ) {

		return( isStructOfType( value, "TYPE_LINKED" ) );

	}


	/**
	* I determine if the given value is a "weak" Struct.
	* 
	* @value I am the value being inspected.
	*/
	public boolean function isWeakStruct( required any value ) {

		return( isStructOfType( value, "TYPE_WEAKED" ) );
		
	}


	/**
	* I determine if the given value is a Struct of the given Type.
	* 
	* @value I am the value being inspected.
	* @valueType I am the name of the INTERNAL TYPE being tested.
	*/
	public boolean function isStructOfType(
		required any value,
		required string valueType
		) {

		// Since we're about to dip into the INTERNAL IMPLEMENTATION details of the
		// Lucee CFML Struct object, let's try to short-circuit the check to avoid any
		// invalid object references.
		if (
			! isStruct( value ) ||
			! isInstanceOf( value, "lucee.runtime.type.StructImpl" )
			) {

			return( false );

		}

		// At this point, we know that we're dealing with a "StructImpl" instance. As
		// such, we should be able to access its Type, which is an enumerated value.
		var StructTypes = createObject( "java", "lucee.runtime.type.Struct" );

		switch ( valueType ) {
			case "TYPE_UNDEFINED": // -1
			case "TYPE_WEAKED":    // 0
			case "TYPE_LINKED":    // 1
			case "TYPE_SYNC":      // 2
			case "TYPE_REGULAR":   // 3
			case "TYPE_SOFT":      // 4

				return( value.getType() == StructTypes[ valueType ] );

			break;
			default:

				return( false );

			break;
		}

	}

</cfscript>

As you can see, I am defining three high-level functions:

  • isNormalStruct( value )
  • isLinkedStruct( value )
  • isWeakStruct( value )

But, each of these just turns around and defers to a low-level method, isStructOfType(), which, in turn, dips into the underlying Java implementation details. The low-level part is the part that might break when Lucee CFML changes its implementation. But, given that it is wrapped up in a Function, it gives us a place to change it later on.

That said, when we run this ColdFusion code, we get the following output:

Different struct types being inspected in Lucee CFML

As you can see, by using our custom User Defined Functions (UDFs), we are able to take a ColdFusion Struct and determine which type it is. I could - theoretically - now take these decision functions and build a MongoDB gateway component that requires linked / ordered Structs to be used to define query document specifications in Lucee CFML 5.3.6.61.

Want to use code from this post? Check out the license.

Reader Comments

89 Comments

I was determining whether an Adobe ColdFusion struct was ordered by examining the canonical Name.

canonicalName = getMetaData(myStruct).getCanonicalName();

For structs, It would return one of the following:

  • coldfusion.runtime.Struct
  • coldfusion.runtime.StructOrdered

If using a LinkedHashMap, it would return:

  • java.util.LinkedHashMap
15,902 Comments

@James,

Oh nice, that's good to know for ACF. And actually, when I started this post, I was assuming that Lucee CFML was going to work the same way. But, it turned out that the low-level Struct was actually a property of the "Struct Implementation", so I had to dip down into the .getType() method. But, nice to see this can be achieved in both runtimes.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel