This is something interesting I came across the other day, when I wanted to dynamically evaluate a static field on a Java class, and I thought it was a clever trick that was worth sharing.
First of all, what is a 'static field'? Well
here is a really good description of a static variable, but the short version is that it something that is available without an instance of a class. This is functionality that can't be done in ColdFusion, but it is available in Java, and some other languages.
So if we look at a
java.lang.Math we can see it has two static fields, one for pi, 'PI' and one for the value of e, 'E'.
In Java, we would be able to access these simply by going:
INT circumference = java.lang.Math.PI * diameter;
and if we wanted to do that in ColdFusion, we would have to do:
<cfscript>
Math = createObject("java", "java.lang.Math");
circumference = Math.PI * diameter;
</cfscript>
Now, what would we do, if we weren't sure if 'PI' existed on the Math class? In Java we'd have to do some
reflection , but in ColdFusion, it is really, really easy:
<cfscript>
hasPI = StructKeyExists(Math, "PI");
</cfscript>
Yes - you can use Struct functions on the Java class to resolve public variables! Interesting, no?
So now, if we wanted to evaluate 'PI', we now have three options:
<cfscript>
piOne = Math.PI; //as before
piTwo = Math["PI"]; //dynamically evaluate
piThree = StructFind(Math, "PI");
</cfscript>
And all three will result in the same value.
This can be very handy when wanting to allow access to Java static fields on Class, but you don't want to be passing around a Java Object - now you can create a Facade to those Java objects, and ask for them dynamically.
I'm sure someone else can come up with a cleverer way to use this trick, but I found it useful.
After quite a few bug fixes and performance enhancements, it made sense to do a maintenance release of
Transfer ORM before moving on to version 0.7.
The major improvements and bug fixes that you will see in this release are:
- Documentation updates.
It was noted that some areas of Transfer were not documented as well as they should. You will now find a brand new 'Getting Started' section, as well as more details in sections such as Caching and Decorators.
- The caching layer now allows the underlying Java engine to discard TransferObjects as required.
This means that as the underlying JVM realises that it is requires more memory, it can discard TransferObjects that aren't being used. This ensures that Transfer won't be a memory leak.
- ModelGlue folder deleted.
You will now find the Model Glue : Unity integration code in the MG:U framework. For more details on how to integrate MG:U will Transfer, go to:
http://www.firemoss.com/blog/index.cfm?mode=entry&entry=F2BFB7B2-3048-55C9-4329FCB6EE13BAB3
- Multiple bug fixes and performance enhancements
Quite a few bug fixes and performance enhancements, mostly to do with the clone() operation, but a few other things as well.
For a full list of changes, you can see the
changelog .
Download Transfer 0.6.1
For a peek at the future, the major enhancements lined up for 0.7 are:
- Soft Deletes
Be able to specify a field in your configuration XML that denotes if a Object is deleted, and have Transfer mange it automatically for you.
- Composite Key support
Quite a few of you have asked for it, now you will get it!
- Transfer Query Language (TQL)
Another nice way to simplify doing gateway list() queries and read() operations, with a simplified SQL like syntax that follows the configuration XML file.
If you have any questions or comments there is a
mailing list , and a
forum .
Ooops! For those of you who were wondering where the readme.txt had gone to in JavaLoader, I accidentally left it off!
I just added it back into the zip file, so if you wanted it, you can re-download it. Sorry about that!
I'm starting to get a little bored of my blog, all I seem to be posting is releases and updates for open source stuff that I have written. So I decided in 2007, I would try and regularly blog all the weird and wacky stuff I just happen to try in my 'test' folder on ColdFusion, and what the results where. Who knows, we may even learn something along the way.
Today's fun and games came from a weird idea I was having with the Decorator pattern, and I thought to myself: 'I wonder what happens if you set another CFC to the SUPER scope within another CFC'.
It's an interesting idea, I mean, at one end of the spectrum it could possibly allow you to dynamically change inheritance at runtime, which could be interesting, at the other end, it could throw a big fat error.
So I decided to write 3 CFCs: Top, Bottom and Super.
Top.cfc sits at the top of the inheritance hierarchy, and looks like this:
<cfcomponent name="Top">
<cffunction name="dothis" hint="" access="public" returntype="string" output="false">
<cfreturn "top">
</cffunction>
</cfcomponent>
That 'doThis()' function is going to be our basis for seeing what happens.
Bottom.cfc extends Top.cfc and looks like this:
<cfcomponent name="Bottom" extends="Top">
<cffunction name="SuperDoThis" hint="" access="public" returntype="string" output="false">
<cfreturn super.doThis()>
</cffunction>
<cffunction name="resetSuper" hint="" access="public" returntype="void" output="false">
<cfset super = createObject("component", "Super")>
</cffunction>
</cfcomponent>
So now we have 2 ways of calling 'doThis()', be can call bottom.doThis() which will go via the usual inheritance mechanism, and bottom.superDoThis(), which will go via super.doThis()
The method resetSuper() will allow us to place a CFC of type Super in the variables scope under the name super.
Super.cfc simply does this:
<cfcomponent name="Super">
<cffunction name="dothis" hint="" access="public" returntype="string" output="false">
<cfreturn "super">
</cffunction>
</cfcomponent>
Which allows us to see what happens.
So in out test bed, we have:
<cfscript>
bottom = createObject("component", "Bottom");
</cfscript>
<cfoutput>
#bottom.doThis()# : #bottom.superDoThis()#
</cfoutput>
And the output from this is:
top : top
So doThis() returns 'top' and superDoThis() return 'top' as well, which is to be expected, as we haven't done anything to change the inheritance structure.
Now, we add this line to it:
<cfscript>
bottom.resetSuper();
</cfscript>
Which overwrites super with the Super.cfc , and we run the same test code again, and the results come back with:
top : super
So doThis() returns 'top' but superDoThis() return 'super', meaning that the 'doThis' found in Super.cfc is actually run instead.
This means that ColdFusion must resolve the variable 'super' before it actually looks up the inheritance tree, however, you can't dynamically change the inheritance structure of the CFC at run time, which would have been a cute trick.
So what can you actually do with this? Honestly, I'm not entirely sure, but it's interesting to know that you can.
I quietly released version 0.3 of JavaLoader today. I'm not sure if anyone actually noticed. Mind you, I didn't actually tell very many people, so I guess I should proclaim a little.
The main purpose of this release is to give greater control over the ClassPath loading behaviour. There are two new optional arguments on the JavaLoader library
loadColdFusionClassPath - this tells JavaLoader whether or not to load the ColdFusion Java libraries.
By default this is set to false.
This is a change from the previous JavaLoader, as it would load all the libraries associated with ColdFusion by default.
loadedClassPathBias - this tells JavaLoader to use a ClassLoader that searches the JAR libraries it has been passed, before it looks to the parent.
This is true by default.
This is also a change from the previous version of the JavaLoader library, which would automatically load the parent's classes before the JavaLoader classes.
This is particularly useful when ColdFusion classes are required, but you need to overload certain libraries that are loaded with ColdFusion.
More details can be found in the readme.txt file inside the JavaLoader download .
For questions or comments, feel free to email me , fire off a message to the forum , or file a bug report .