Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Ryan Anklam

How ColdFusion CreateObject() Really Works With Java Objects

Posted by Ben Nadel
Tags: ColdFusion

I use ColdFusion's CreateObject() method at least a dozen times each day to create wonderful Java objects like String Buffers and File Input Stream. Until recently, I have never really thought about how it actually works - I have just accepted that the black magic under the hood did the job properly. But then, just the other day, I discovered that you could instantiate multiple Java instances off of the same Java class returned by CreateObject():

  • <!--- Get the string buffer class object. --->
  • <cfset objStringBuffer = CreateObject(
  • "java",
  • "java.lang.StringBuffer"
  • ) />
  •  
  • <!---
  • From the string buffer class object, instantiate
  • two sepparate instances of the Java string buffer.
  • --->
  • <cfset objDataOne = objStringBuffer.Init() />
  • <cfset objDataTwo = objStringBuffer.Init() />

When I saw this, I realized that I had no idea how ColdFusion's CreateObject() functionality really worked. After some posting and some back and forth comments, Sammy Larbi, Rupesh Kumar, and Sean Corfield have really helped to clear things up:


 
 
 

 
ColdFusion CreateObject() Functionality For Java  
 
 
 

Apparently, when you call ColdFusion's CreateObject() method to create a Java object, ColdFusion is returning a proxy object to that Java object, not the Java object itself. This proxy object allows you to reference static properties and invoke static methods of that Java class without actually having to instantiate the full Java class. This is good for memory usage and for performance (object instantiation is a costly process).

If you call Init() on that proxy object, it then instantiates the Java object with the given arguments and returns a proxy object wrapped around this new instance (I suspect from the Init() example above that it must create a new proxy object otherwise you probably wouldn't be able to call Init() twice on the same ColdFusion proxy). Similarly, if you attempt to call a non-static method of the Java class, the proxy object will, behind the scenes, call Init() on the Java class (passing no arguments), and use that as the target class going forward.

Of course, this is what I think I understand. This may contain errors and if I get feedback on this, I will update the graphic as necessary. Thanks to all who helped me get this far.




Reader Comments

you can also create WebService objects this way.

i.e.:
<cfscript>
dynamicsWS = CreateObject("webservice", "http://192.168.0.100/DynamicsGPWebServices/DynamicsGPService.asmx?WSDL");
</cfscript>

<cfinvoke webservice="#dynamicsWS#" method="GetCompanyList" refreshWSDL="yes" timeout="30" returnvariable="result">
</cfinvoke>

This creates WebService object in your ColdFusion instance (available from administration panel -> webservices) and this object "lives" in there for about 10 (gets deleted if not used).

So I never took CreateObject() for granted :)

Reply to this Comment

@Dmitry,

Word up - createObject() can do a whole bunch of things. It's probably one of the best updates to the language.

Reply to this Comment

Ben, sheds some light on the subject for me. I've recently ventured into a shared hosting enviroment to do some outside work, and quickly ran into the java object disabled issue.

I'm not much of a programer, more a manager and integrator and struggling to find a workaround for some open source I'm using.

Thanks for the overview.

Reply to this Comment

@Scott,

Glad you liked it. I'm sorry to hear that your Java objects have been disabled on the host. That can definitely get annoying :(

Reply to this Comment

One quick point: I'm less certain that "object instantiation is a costly process" - object instantiation is strongly optimized on the JVM, and even reflection has far less cost than before.

IMO, the reason for the init pattern is to allow access to statics with less hoops; though this creates a somewhat schizophrenic API.

Nitpicks aside, thanks for another clear and lucid explanation of one of the details of the CF platform. Your blog has been extremely helpful to me as I learn!

Reply to this Comment

I know this is a bit of an old thread, but I recently discovered something relevant. The init() function call on CF proxy objects is not thread safe.

Recently we began having random documents inserted into the incorrect collection on our MongoDB. We tracked it down to our own Mongo driver which leverages the Mongo Java driver as a singleton. However, in concurrency situations, creating new instances of our java class using the above method caused us sometimes to get the wrong instance back.

For example:
Process A calls init("collection1")
Process B calls init("collection2")
Both calls return CF proxy objects with the same instance of our CFMongo class pointing to collection2.

So if you are going to cache your static class in a shared location, like the application scope, you need to only call init() with an exclusion lock. In our case we chose to use CreateObject() each time passing the mongo driver singleton into the constructor.

Reply to this Comment

Hi Ben, interesting post.

It looks like I'm running into the CF proxy object as an issue on a routine I'm writing.

I'm importing the Amazon Web Services SDK for Java into a CFC and to initialise the S3 Client you first have to create an authentication object. However passing this object (which is created correctly) to the init() function throws an "An exception occurred while instantiating a Java object. The class must not be an interface or an abstract class" error.

I'm guessing that because this isn't a true Java object the second class doesn't like it?

Anyway here's the code:

  • awsCred = createobject('java',
  • 'com.amazonaws.auth.BasicAWSCredentials').init(
  • accessKey,
  • secretKey
  • );
  • // this works fine; CFDUMP shows correctly instantiated object
  •  
  • s3 = CreateObject( 'java',
  • 'com.amazonaws.services.s3.AmazonS3Client'
  • ).init(awsCred);
  • // this line throws the error

Any ideas how to instantiate a real Java object?

Thanks
James

Reply to this Comment

Ignore my earlier post, it appears that the Amazon SDK requires some more third party Jar files in the class path than it comes with, namely httpclient-4.1.1.jar if you're having similar problems.

Reply to this Comment

Post A Comment

?
You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.