Comparing ColdFusion Struct Equality With Java

Posted August 21, 2006 at 6:15 PM by Ben Nadel

Tags: ColdFusion

I am really loving this whole Java thing. Have you ever wanted to compare two different Structs in ColdFusion? Maybe do something like:

  • <!--- Set up one struct. --->
  • <cfset objGirlA = StructNew() />
  • <cfset objGirlA.Name = "Sarah" />
  • <cfset objGirlA.IsHottie = "Yes" />
  • <cfset objGirlA.Measurements = ListToArray( "36,28,36" ) />
  •  
  • <!--- Set up another struct. --->
  • <cfset objGirlB = StructNew() />
  • <cfset objGirlB.Name = "Sarah" />
  • <cfset objGirlB.IsHottie = "Yes" />
  • <cfset objGirlB.Measurements = ListToArray( "36,28,36" ) />
  •  
  • <!--- Test for equality. --->
  • <cfset blnIsEqual = (objGirlA EQ objGirlB) />

If you ever have, then you know this throws the following error:

Complex object types cannot be converted to simple values. The expression has requested a variable or an intermediate expression result as a simple value, however, the result cannot be converted to a simple value. Simple values are strings, numbers, boolean values, and date/time values. Queries, arrays, and COM objects are examples of complex values.

No such luck. However, if you grab the Java methods on ColdFusion structs, such a thing is indeed possible. Structs have the Java method, Equals():

  • <cfset blnIsEqual = objGirlA.Equals( objGirlB ) />

This compares the passed struct, objGirlB, to the calling struct, objGirlA. And, you guessed it, it works just fine.

There are, however, some caveats. You can only compare simple values. Well, that's not exactly true; you can only compare values that are passed by value (not by reference), from what I can see. This includes numbers, strings, dates, and even arrays. In the above example, the Measurements key gets compared successfully even though it is an array and considered complex. If you have any keys that have components or Java objects, they are not compared; it doesn't throw an error, but I don't think any comparison is taking place. For instance, these two structs:

  • <!--- Create one with hotness 10. --->
  • <cfset objGirlA = StructNew() />
  • <cfset objGirlA.Name = "Sarah" />
  • <cfset objGirlA.Hotness = CreateObject( "component", "Girl" ).Init(
  • hotness = 10
  • ) />
  •  
  • <!--- Create one with hotness 9. --->
  • <cfset objGirlB = StructNew() />
  • <cfset objGirlB.Name = "Sarah" />
  • <cfset objGirlB.Hotness = CreateObject( "component", "Girl" ).Init(
  • hotness = 9
  • ) />

 

... when compares are evaluated as the same. The differences in hotness (10 vs. 9) does not get taken into account.

Anyway, not sure how useful this is, but sort of nifty little thing.



Reader Comments

May 14, 2009 at 7:07 PM // reply »
1 Comments

Be careful when using this technique. There are some strange quirks with using equals() with ColdFusion numbers. For instance:

<cfset a = structNew() />
<cfset a.n = 2 />

<cfset b = structNew() />
<cfset b.n = 2 />

<cfoutput>
#a.equals(b)#
</cfoutput>

The above outputs "YES" as expected. But if we change b.n to 1+1:

<cfset a = structNew() />
<cfset a.n = 2 />

<cfset b = structNew() />
<cfset b.n = 1 + 1 />

<cfoutput>
#a.equals(b)#
</cfoutput>

it now outputs "NO"!


May 19, 2009 at 9:35 AM // reply »
10,640 Comments

@Tony,

Hmm, very interesting. I never ended up using this anywhere; but it's good to know about these issues. Thanks.


Sep 17, 2009 at 9:14 AM // reply »
10 Comments

This is a great tip, thanks! Was already thinking about first converting the structs to wddx, but that didn't feel right. Will use this a lot, I guess!


Mar 26, 2010 at 7:01 PM // reply »
5 Comments

@Tony Wu

If you change it to <cfset a.n = val(2) /> in the second example you get a yes. It has to do with cf implicit type conversion.


Apr 21, 2010 at 9:15 PM // reply »
21 Comments

@Tony Wu

In your example, the reason for the "NO" is because a.n is created as a java.lang.String and b.n is created as a java.lang.Double - eg.

<cfset a = structNew()>
<cfset a.n = 2>

<cfset b = structNew()>
<cfset b.n = 1 + 1>

<cfoutput>
#a.equals(b)# (NO)
#a.n.getClass().getName()# (java.lang.String)
#b.n.getClass().getName()# (java.lang.Double)
</cfoutput>

to force a.n to be a Double, <cfset a.n = 2 + 0>
to force b.n to be a String, <cfset b.n = 1 + 1 & "">

You could bounce the a and b structs through serializeJSON and deserializeJSON, which makes both numbers java.lang.Strings, but has other side effects - wouldn't recommend it...

Doubles and Longs, when compared, return true
eg.

<cfset c = structNew()>
<cfset c.n = createObject( 'java', 'java.lang.Long').init(2)>

<cfset d = structNew()>
<cfset d.n = 1 + 1>

<cfoutput>
#c.equals(d)# (YES)
#c.n.getClass().getName()# (java.lang.Double)
#d.n.getClass().getName()# (java.lang.Long)
</cfoutput>

I am guessing this is the case as both Double and Long extend the java.lang.Number class. If that's the case, Short, Integer, Float, BigInteger and BigDecimal would also return true when compared (and of course the values are the same)


Feb 8, 2011 at 6:01 AM // reply »
1 Comments

Thanks. This is really useful.


Oct 4, 2011 at 5:20 PM // reply »
10 Comments

Looks like others have hit the same issue I've just hit, having to do with Boolean variables. I was attempting to serialize a structure to JSON, then deserialize the data and compare the deserialized version to the original structure, like this:

<cfset myStruct = {
bla = "hello",
ble = 5,
blo = true
}>

<cfset myJSON = deserializeJSON(serializeJSON(myStruct))>
<cfoutput>#myStruct.Equals( myJSON )#</cfoutput>

Equals() in this case returns NO, because the boolean value for "blo = true" gets converted to "YES" during the JSON round-trip. If I pull that variable out of the structure, then Equals() returns true.

Really annoying, and sort of a show-stopper. Unless I'm missing something.


Oct 5, 2011 at 10:54 AM // reply »
10 Comments

I should follow up and say that perhaps this post wasn't the right place for my comment, given that it's really a problem with how CF handles JSON, and not with the Equals() function. Had I done a little more Googling prior to posting, I would have seen that the CF community has its fair share of issues with CFJSON.

The one new wrinkle for me, though, is that the JSON round-trip took something that was a boolean and converted it to a string. I've seen others complain about the opposite: CFJSON taking a "yes" or "no" string value and converting it to a boolean. So it's weird that CFJSON manages to get both directions wrong.

Of course, I'm happy to be misinformed on this front, so if anybody can tell me what I'm doing wrong, if it's something obvious, I'd be glad for the education.


Post A Comment

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.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »
Feb 9, 2012 at 10:29 PM
Learning ColdFusion 9: Application-Specific Data Sources
@Ben, No offence, but if people were really wanting advanced features they would be using a platform like ASP.NET MVC. CFML is so structurally compromised as a tag-based scripting language that ... read »
Feb 9, 2012 at 10:03 PM
Subversion - Cleanup Failed To Process The Following Paths
@Leviaguirre, do you still have problems with this? ... read »