Skip to main content
Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.

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

By Ben Nadel on
Tags: ColdFusion

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.



Reader Comments

What has two thumbs and hopes you leave a comment? This Guy! (Ben Nadel).

Post A Comment

You — Get Out Of My Dreams, Get Into My Blog
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.