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 Scotch On The Rock (SOTR) 2010 (London) with:

Creating Multiple Instances From The Same Java Class In ColdFusion

By Ben Nadel on
Tags: ColdFusion

The other day, I came across a cool little feature of ColdFusion that I was not aware of. Usually, when I go to create a Java object, I use the ColdFusion CreateObject() method and give it the Java class name that I want to create. I don't fully understand that magic that is CreateObject() and so, I assumed that you needed to call it for every single Java object that you wanted to create.

As it turns out, though, you only need to create the Java class once and then you can call the constructor method, Init(), on it as many times as you want. Check out this simple demo that utilizes one java.lang.StringBuffer class to create two StringBuffer instances:

  • <!---
  • Create a class of the Java string buffer.
  • From this class, we are then going to instantiate
  • new StringBuffer instances.
  • --->
  • <cfset objStringBuffer = CreateObject(
  • "java",
  • "java.lang.StringBuffer"
  • ) />
  •  
  •  
  • <!---
  • Create two string buffer objects by calling
  • the constructor on the ONE StringBuffer class.
  • --->
  • <cfset objBufferA = objStringBuffer.Init() />
  • <cfset objBufferB = objStringBuffer.Init() />
  •  
  •  
  • <!--- Add some text to string buffer A. --->
  • <cfset objBufferA.Append(
  • "Put it in my A!"
  • ) />
  •  
  • <!--- Add some text to string buffer B. --->
  • <cfset objBufferB.Append(
  • "Put it in my B!"
  • ) />
  •  
  •  
  • <!---
  • Output the two different string buffers. I do not
  • expect them to be different, but I have never called
  • Init() twice on the same object, so I am not sure
  • how it will work.
  • --->
  • <p>
  • BufferA: #objBufferA.ToString()#<br />
  • BufferB: #objBufferB.ToString()#
  • </p>

Running the above code, we get:

BufferA: Put it in my A!
BufferB: Put it in my B!

Each Init() call created a new StringBuffer instance that received it's own Append() data. How freakin' cool is that? I am sure those of you who are more Java-savvy are looking at that and thinking, "Well yeah - how else did you expect it work?" Yeah, well I don't know that stuff :) I guess the CreateObject() returns a class definition and then the Init() method is reflectively calling the "new" constructor on that class definition or something? It's all voodoo to me.




Reader Comments

Well, yeah I might have asked "how did you expect it to work," =) except that I see the issue where I think confusion can arise. I would have thought (if I had not ever done it) that create object created the object and returned it, and thus you would be calling the constructor of an already constructed object, since thats how we do it in CF.

Its too bad they didn't just make constructors a default part of the language. I see why it might be difficult to do now (although, I think someone who thought about it long enough might find a way to do it that won't break anything). Then, we wouldn't have a disconnect between the way it works for Java and the way it works for CF.

Reply to this Comment

@Sam,

Can you give me the 2 second run down on what CreateObject() is actually returning? I assume is has something to do with the difference between a class and an instance of that class??

Like, when I think about Java (and I haven't coded it in years, so this might be incorrect), I think:

String foo = new String( "bar" );

To me that is one statement, so it was not obvious to me that object instantiation through ColdFusion would be in two parts - CreateObject() and then Init().

Reply to this Comment

I had never thought to look until you just asked. So, I looked and I'm getting funny things happening.

If I do this (notice no initialization of sb):

<cfset sb = CreateObject("java","java.lang.StringBuffer")/>
<cfset sb2 = sb.init()>
<cfset sb.append("hello")>
<cfset sb2.append("wassup?")>

<cfoutput>
#sb.ToString()#<br/>
#sb2.ToString()#
</cfoutput>

Both sb and sb2 are the same object.

But if I do this (addition of sb3):
<cfset sb = CreateObject("java","java.lang.StringBuffer")/>
<cfset sb2 = sb.init()>
<cfset sb3 = sb.init()>
<cfset sb3.append("hello")>
<cfset sb2.append("wassup?")>

<cfoutput>
#sb3.ToString()#<br/>
#sb2.ToString()#
</cfoutput>

They are different objects.

And finally, if I do this:

<cfset sb = CreateObject("java","java.lang.StringBuffer")/>
<cfset sb2 = sb.init()>
<cfset sb3 = sb.init()>
<cfset sb3.append("hello")>
<cfset sb2.append("wassup?")>

<cfoutput>
#sb.ToString()#<br/>
#sb2.ToString()#
</cfoutput>

(notice we are outputting sb, NOT sb3) they are different objects with sb == sb3 != sb2.

So in short, I'm clueless as to what's actually going on. But I would have guessed at something like createobject was returning an object of type Class which represented StringBuffer (not sure if I'm saying that correctly or not, but I think you get the idea)

Reply to this Comment

Oh, and I should have said (in the last bit) that clearly, that doesn't appear to be the case (createObject returning an object of type Class that represented StringBuffer).

Reply to this Comment

Hi Ben,
CreateObject for a java class, simply creates a proxy for the class. Thus at this point, only the class gets loaded. Its only when you call a constructor explicitly using 'init' or when you call a non-static method, the class gets intantiated.
Probably the reasons it is like this are

1. If all you need to call is a static method, why to instantiate the object unnecessarily. Object instantiation is costly.
2. We wanted to keep the syntax clean. For createObject to return the actual object, it would require all the constructor arguments here itself, which will complicate the syntax.

Rupesh

Reply to this Comment

@Sam,

Thanks for doing a little digging.

@Rupesh,

That sounds pretty good. I need to study up on my Java to really fully contact with what it is you are saying. I just need to wrap my head around what a Class is vs. what an object is. Thanks!

Reply to this Comment

"I guess the CreateObject() returns a class definition and then the Init() method is reflectively calling the "new" constructor on that class definition or something? It's all voodoo to me."

You guessed correctly.

This behavior is what allows you to manipulate the static methods and data in a Java class within ColdFusion.

There's a gotcha to be aware of tho'... once you have your class (definition), if you attempt to reference any non-static method or data before calling init(), ColdFusion will automatically call init() with no arguments for you. That's how you can access some Java objects without explicitly calling init() with no arguments.

I don't know whether it will still allow you to call init() explicitly to create a new instance but it's something to be careful about...

Reply to this Comment

Thanks for your all the feedback and tips. This has all helped me to clear up the confusion in my mind. I like being able to do this.

Reply to this Comment

@William,

Honestly, I think reading the documentation is really one of the best ways to get the basic understanding of all that the language has to offer. Then, try a mini project that gets the gears working in your head. Learning by goal-oriented doing is the best.

And then, on top of that, I am always willing to write up a demo of something if you get stuff.

Reply to this Comment

Hi,

Once an external class file has been instantiated through cfobject it remains cached until the CF App service is restarted. Are you aware of any way to flush out the cached class (under web-inf/classes) without restarting the CF app service?

Thanks,

Ben

Reply to this Comment

@Ben,

I am not sure about that. To be honest, I am not even really sure what you are talking about :) Sorry, I wish I was more help.

Reply to this Comment

Sorry about the confusion. What I was asking was THAT pertinent to the topic, but I've been researching this all over and have found very little. Anyway, here is some background and what I'm trying to figure out (I'm including some sample code that you can test this with as well).

Scenario:
Create an external Class file. Copy and save the compiled file to the cf_root/wwwroot/web-inf/classes folder. Now instantiate it with cfobject. Great! You can read the file and see it via your CFM page. Now go ahead and make a change to the java file, compile it and save over the new "modified" class file to the cf_root/wwwroot/web-inf/classes folder. Run your CFML code again and it will read the initial cached file. Heck, delete your class file in the cf_root/wwwroot/web-inf/classes folder and CF will still read the cached file. The only way to force CF to read the new file is to restart the CF App service.

Here is some sample code:
Java:
===============
package ClassReload;

public class ReloadTest{
public ReloadTest(){

}
public String GetReload(){
return "This be version UNO!!";
}
}
===============

save the resulting class file to the web-inf/classes folder and run the following CF code:

<cfobject action="create" type="java" class="ClassReload.ReloadTest" name="TestClassReloading">
<cfdump var="#TestClassReloading.GetReload()#">

Great! You'll see "This be version UNO!!"

Now go ahead and change your return value to be something else "This be version TWO!!". Recompile and save to the web-inf/classes folder. Run your CF code again and you'll still see "This be version UNO!!". The only way I can see the new class file is by restarting the CF App service.

I have followed the suggestions at the following to no avail:
http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_18228&sliceId=2
or
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Java_2.html
In both cases scroll to where you see the "class loading" or "dynamic class loading" part.

Sorry for the long post, but I hope it makes sense.

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.