Post-Instantiation CFC Method References Don't Show Up In CFDump In ColdFusion 9

Posted July 20, 2010 at 9:56 AM by Ben Nadel

Tags: ColdFusion

Last week, I came up against a really strange issue in ColdFusion 9. I was trying to build some ColdFusion components on the fly and I was using CFDump to test my algorithm. Unfortunately, it seemed that something was going very wrong; no matter what I did, I couldn't get the assembled methods to work. Or, at least they didn't appear to be working according to CFDump. After banging my head against a wall for a while, I finally tried to execute one of the methods out of desperation and to my surprise, it worked fine! Apparently, in ColdFusion 9, methods appended to a ColdFusion component after it has been instantiated don't actually show up in CFDump.

To demonstrate this, I created the following Test ColdFusion Component:

Test.cfc

  • <cfcomponent
  • output="false"
  • hint="I am a test component.">
  •  
  •  
  • <cffunction
  • name="init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return an initialized component.">
  •  
  • <!--- Copy the stub file to another key. --->
  • <cfset this.innerCopy = this.stub />
  •  
  • <!--- Return this object reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="stub"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="I return a string.">
  •  
  • <cfreturn "Hello there." />
  • </cffunction>
  •  
  • </cfcomponent>

As you can see above, the init() method, which executes after instantiation, copies the "stub" method reference into the key, "innerCopy." Then, I created a test script which instantiated this component and even tried to append another method reference:

  • <!--- Create an instance of our test component. --->
  • <cfset test = createObject( "component", "Test" ).init() />
  •  
  • <!--- Copy the stub method to another key. --->
  • <cfset test.outerCopy = test.stub />
  •  
  • <!---
  • At this point, we have an inner copy and and outer copy of
  • the stub file in the test component. Let's CFDump out the
  • component to see if those keys show up.
  • --->
  • <cfdump
  • var="#test#"
  • label="Test Component"
  • />
  •  
  • <br />
  •  
  • <!--- Let's also dump out the key list. --->
  • <cfdump var="#structKeyList( test )#" />

When I run the above code in ColdFusion 9, I get the following CFDump:

 
 
 
 
 
 
ColdFusion 9 CFC Method References Do Not Show Up In CFDump If Added After Instantiation. 
 
 
 

As you can see, only the compile-time methods, init() and stub(), actually show up in the CFDump. However, when I output the structKeyList(), I get all of the following:

INNERCOPY,OUTERCOPY,stub,init

This behavior is a change from ColdFusion 8. In CF8, the new method references would show up in both the CFDump and the key list. I don't know if this is a bug - it feels like one. Perhaps it has been fixed in the CF9.0.1 Updater (I have not yet upgraded). All to say, be careful in ColdFusion 9 if you are using CFDump to help debug your ColdFusion components - it might not show you what is truly going on.




Reader Comments

Jul 20, 2010 at 10:31 AM // reply »
1 Comments

ORM components (as I just tweeted you) seem to show a similar problem...

For example, changing the property "price" to "money" would let me invoke "getMoney", but it would still dump as "getPrice".

Only a full CF restart would solve this, as ormRestart was uneffective.

I was running 9.0.1, so probabily your bug is still there, too..


Jul 20, 2010 at 10:36 AM // reply »
11,238 Comments

@Ludovico,

That's very interesting that it would let you access the correct method, but still CFDump the wrong one. That's kind of crazy. I guess with all the ORM stuff, they start optimizing how the properties were introspected or something. They must have erred on the side of "static" of performance reasons.


Jul 20, 2010 at 11:17 AM // reply »
24 Comments

I wonder if this is related to the issue I pointed out with injected methods not showing up in getMetaData() in CF.

http://objectivebias.com/entry/injected-methods-show-up-in-component-metadata-in-railo-but-not-coldfusion


Jul 20, 2010 at 11:19 AM // reply »
11,238 Comments

@Tony,

Yeah, definitely sounds like they are very related. I always feel a bit foolish when I blog something, then see *my* comments in a related post :)


Jul 20, 2010 at 3:40 PM // reply »
14 Comments

I also discovered this when I was writing a nifty service object for ORM, and then using a factory that injects the methods into a CFC upon creation.

Except I didn't notice that it used to work in CF8. I thought it was just old news.

Thanks!


Jul 20, 2010 at 3:42 PM // reply »
11,238 Comments

@Joshua,

I only noticed the CF8/CF9 discrepency because I was specifically writing something to work in both languages (with some CF9 *features* when available). That's what was so confusing - the CF8 CFDump worked and CF9 was not working. I was convinced I was doing something wrong.


Jul 20, 2010 at 4:03 PM // reply »
25 Comments

Hi Ben
I don't think it's injected methods, per se, because if you inject a NEW function into the CFC, then it shows up in the dump just fine, eg:

<cfset o = createObject("component", "Cf9InjectedMethods")>

<cffunction name="g" access="public" returntype="boolean" output="false" hint="g()'s hint.">
<cfargument name="b" type="boolean" required="true" hint="A boolean arg">
<cfreturn not arguments.b>
</cffunction>

<cfset o.g = g>

<cfdump var="#o#">

And this works the same if one grabs a method from an instance of a different CFC (but not another instance of the same CFC).

I guess it's only one instance of each class (ie: the classes CF creates under the hood... each method gets its own class, for some reason) that gets displayed in <cfdump>

I reckon this is a bug. Have you raised it as one? I'll vote for it, if so.

--
Adam


Jul 20, 2010 at 8:42 PM // reply »
11,238 Comments

@Adam,

Good insight. I wonder what kind of logic is being performed under the hood in the CFDump. Especially if the key does show up in structKeyList(), you'd think the CFDump logic would pick it up.... unless a Collection Loop wouldn't see the keys either.


Jul 21, 2010 at 4:57 AM // reply »
8 Comments

The cfdump documentation does not provide any informations on hiding the CFC method references. On the other hand, looping over the "test" collection doesn't miss any of its keys, so this would mean that the references are partially exposed which looks kinda buggy.

Instead, the getMetaData function, which is supposed to reveal "substantially more data about the CFC than the cfdump tag shows" did not offer any information regarding the method references at any time during the existence of ColdFusion 7-9. So, maybe this should be the main behaviour of the cfdump as well, who knows? Anyway, this should be documented as the default behaviour has been changed starting with CF9.

But, if you want to completely expose those references, you could do something like this

<cfset this.references.innerCopy = this.stub />
<cfset test.references.outerCopy = test.stub />

though this is definitely not the same thing as expected in the first place.


Jul 22, 2010 at 10:26 PM // reply »
11,238 Comments

@Edy,

It definitely feels like a bug to me. And, as @Adam pointed out above, this only happens when *existing* function references are duplicated within a component. My guess is, they changed something and simply didn't come across the problem in testing ... especially since this kind of approach would not have had any use at all before the introduction of getFunctionCalledName().


Sep 23, 2010 at 3:25 PM // reply »
25 Comments

I've experienced something similar with cfdump, where complex types specified as properties in a CFC are displaying their methods with the CFC methods after instantiation. I'm not extending the CFC but just declaring a property and generating the accessors and mutators dynamically by setting the accessor attribute to true. The methods don't actually exist in the cfc and can't be access, which is correct but the ColdFusion displays them as native methods within the hierarchical dump. Weird!


Sep 23, 2010 at 3:43 PM // reply »
11,238 Comments

@Hussein,

The good thing is that it doesn't affect run-time functionality; it's just confusing when you are trying to debug your code.


Nov 17, 2010 at 4:13 PM // reply »
149 Comments

This is driving me crazy. I can't figure out a way to pull in a cffunction from a file where it's the only code in the file and inject it as a function or any other type of variable into a cfc instance outside of the pseudo constructor. Has anyone else ever figured this out?

The only workaround I can think of is having a skeleton cfc that reacts to some global scope variable ( request for example ) and cfincludes the files in its pseudo constructor which I could instantiate and then copy from, but that seems double dog hacky. Ideas?


Nov 17, 2010 at 4:17 PM // reply »
11,238 Comments

@David,

You can CFInclude a function from within another function. The caveat is that is makes the function private. However, after you include it, I think you can then copy it to the public scope:

  • <cfinclude template="myUDF.cfm" />
  • <cfset this.myUDF = variables.myUDF />

Try that?


Nov 17, 2010 at 4:20 PM // reply »
149 Comments

AHA! Ignore that it was just a scoping issue. For some reason compile time cffunctions are accessible through both this and variables while runtime injected ( through cfinclude at least ) cffunctions from anywhere outside of the pseudo constructor go straight into the variables scope only. HOORAYYYYYYY.


Nov 17, 2010 at 4:21 PM // reply »
149 Comments

Oops, sorry Ben. Thanks! Had this page open and wrote my 2nd comment before I got the email about your response.

I dare you to make your blog posts comety and push comments to them as authored.


Nov 17, 2010 at 4:22 PM // reply »
11,238 Comments

@David,

I like the idea of pushing comments :) Hmmm. I'd love to carve out a few weekends actually and totally re-build this blog architecture from the the ground up.


Dec 1, 2010 at 9:54 AM // reply »
19 Comments

This may be a stupid question. I want to get just the properties of a cfc and not the methods. How do I get that?

ex:
<cfcom..>
<cfparam name="THIS.xx" default="HI"/>

<cffun..>
function code
</cffun..>

</cfcomp..>

cfm page
<cfset a = createobject(..)/>

<cfdump var="#a#"/>

When I do this I get the properties but also the methods. How do I just get the properties(cfparams,THIS)?


Dec 1, 2010 at 10:37 PM // reply »
11,238 Comments

@Kevin,

There's no single-step way to do that that I know of since the component is basically just a container of variables, some of which are methods, some of which are properties.

If you are just using the CFDump tag, later versions of ColdFusion have an attribute where you can actually hide the UDFs:

<cfdump var="#a#" showudfs="no" />

However, I suspect that you want more than just CFDump. In that case, you would have to CFLoop over the keys in the component and check them with the native function:

isCustomFunction( component[ key ] )

That will return true for all methods. You can just ignore those in your case.


Dec 2, 2010 at 10:33 AM // reply »
19 Comments

@Ben,

Ah thank you.
By the way I was looking around and saw a few items about components. Is there a best practice when it comes to properties?
ex:
<cfparam name=THIS.xxx" default="0"/> - someone said this was bad practice.
or
<cfset THIS.xxx = 0/>
or
<cfproperty..../>


Dec 5, 2010 at 1:50 PM // reply »
11,238 Comments

@Kevin,

It depends on what your intent is. If you're in a situation where you want to set a default value for something like a new CFC, then I would just set it explicitly:

<cfset this.property = defaultValue />

However, if you are dealing with a situation where you are not sure if a value will exist (say for example, in a form post), that is where I use CFParam all the time:

<cfparam name="form.property" default="" />

Of course, that's typically outside of a CFC (or, at the least, refers to non-CFC properties). If you are trying to initialize a CFC, I would go with the former approach - an explicit set.

The CFProperty tag is only meaningful if you are using synthesize getters/setters in CF9+. Before that, the only use for CFProperty was web service information and what ever kind of "meta programming" you might be doing. I don't think I have ever used them outside of CF9+, though.



Post A Comment

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.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 19, 2013 at 2:31 PM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
It's funny really just how well that image describes the way I would imagine most people that go with angular for some project is. I have had a similar roller-coaster ride with it as well, but not qu ... read »
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools