Testing for Equality in ColdFusion

posted by Chris on Dec 15, 2010 at 22:45

I had a long chat with Bob Silverberg last night about how to test for equality between objects in ColdFusion and just noticed that Ben Nadel mentioned a very similar issue in his post on creating proxy components where he wanted to test for object reference equality, ie two variables pointing to the same object in memory.  So i thought i'd write up what we discovered.  

 

The problem I was discussing with Bob was how to test if the value of two objects was the same, the objects would typically be a ColdFusion Component of which we would have no knowledge of the properties or methods.  For the purposes of this post i'm using a simple CFC with a single property id.

// Test.cfc
component {
	property name="id";
}

My first thought was that you should be able to use java's equals() method, like this

x = structNew();
y = structNew();
result = x.equals(y);

You can compare structs like this with no problem, so it might work for CFC's ?

x = new Test();
y = new Test();
result = x.equals(y);

However this doesn't work because Test.cfc has no method named equals. My guess is that all method calls on a CFC are intercepted as part of the implementation of the onMissingMethod functionality added in CF8 so theres no way to get at the equals method, directly. 

 

Mark Mandel, author of the brilliant JavaLoader jumped in to show us how to get at the equals method using reflection

// get the current classloader
classLoader = getClass().getClassLoader();
// load the class for java.lang.Object
objectClass = classLoader.loadClass("java.lang.Object");
// get the equals method
equalsMethod = objectClass.getMethod("equals", [objectClass]);

x = new Test();
y = new Test();

// invoke equals in the context of x passing y as an argument
// this is equivalent to x.equals(y)
result = equalsMethod.invoke(x,[y]);

Clever stuff, but what about Ben's problem of object reference equality.  We'll there is a reasonably simple answer to this one but it does require a little bit of java. So far i've only talked about java's equals() method which tests for equality by value, however the == operator in java tests for equality by reference.  

 

First I've created a really simple java class with two methods, one will do a comparison using equals(), the other with the == operator.  Compile it and drop it in your WEB-INF/classes directory, or load it using JavaLoader

public class SimpleComparator {
	public boolean sameByValue(Object obj1, Object obj2) {
		return obj1.equals(obj2);
	}
	public boolean sameByReference(Object obj1, Object obj2) {
		return obj1 == obj2;		
	}
}

Then in CF

<cfscript>
comp = createObject("java", "SimpleComparator");
x = new Test();
y = new Test();
z = y;
</cfscript>
<cfoutput>
x = y By Value: #comp.sameByValue(x, y)#<br>
x = y By Reference: #comp.sameByReference(x, y)#<br>
y = z By Reference: #comp.sameByReference(z, y)#
</cfoutput>

outputs:

x = y By Value: YES 
x = y By Reference: NO 
y = z By Reference: YES

 

So if your juggling lots of objects around in your application and need to test if your references point to the same object in memory then your sorted

 

Categories:

Comments

Bob Silverberg on Dec 24, 2010 at 17:25
Didn't you mention to me later that one could avoid the whole Java equals thing by simply putting each component into a struct and then using equals on the struct? Does that work reliably? If so it's a much simpler solution.
Chris on Dec 25, 2010 at 10:09
Yeah I did, must have been after I posted this. I'll post an update soon as there's also been some interesting comments on Ben Nadel's post that i linked to.
Ben Nadel on Jan 08, 2011 at 02:12
Cool idea to create the comparator class in Java. ColdFusion, in general, seems to only compare equality by value. If you look at the CF9 functions for arrayFind() or arrayContains(), you might think that that works by reference; but no - objects of a similar "look" are considered the same.

Anyway, thanks for digging into this; very cool to see more Java being leveraged these days.