Testing for Equality in ColdFusion
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
Comments
Anyway, thanks for digging into this; very cool to see more Java being leveraged these days.