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 »
11,238 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 »
22 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.


Jun 25, 2012 at 7:20 PM // reply »
1 Comments

I had the same issue - there are several times that the java "equals" method does not return the expected value.

On researching this, I found this User Defined Function by Milan Chandna that defines 3 complex compare functions - structCompare(St1,St2), arrayCompare(arr1,arr2) and queryCompare(q1,q2).

The file is called complexCompare.cfm, and is available on his blogspot at

http://milanchandnacf.blogspot.com/2012/02/equate-arrays-structs-query-or-possible.html

I ended up using this, and it works more reliably than the .equals method....in my case, I retrieved a complex structure from a data table with many associated tables, creating a structure with arrays of structures in them. I then made a copy of the original structure in session variables, and used the original structure as values in a form, allowing the users to edit these values. In the file handling the submission of the form (where the original structure was lost), I re-created the structure using the form field variables.

Even when I made no changes to the various fields in the form, the .equals method returned FALSE all the time, while the structCompare function returned true....

I hope this helps....

Vinay Mehta.

P.S. - Ben, I have been lurking and learning for a couple of years now...I am glad to be able to finally contribute!


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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools