Automatic Type Conversion in ColdFusion 11 - coldfusion

I am migrating an application from ColdFusion 9 to ColdFusion 11.
In the existing code there is an assignment of a variable to false:
<cfset VARIABLES.roleTypeId = false >
And then, farther down, a function that expects this variable to be numeric:
<cffunction name="rolesForStudy" >
<cfargument name="id" hint="Study Id">
<cfargument name="roleTypeId" default="#VARIABLES.roleTypeId#" type="numeric"/>
</cffunction>
I inherited the code, and I cannot defend the original programmer's decision to set it up this way -- but, in short, it worked in ColdFusion 9, and it doesn't work in ColdFusion 11 (returning a data type error). I assume that ColdFusion 9 was automatically converting false to 0.
My question: Is there a configuration setting that I can change in ColdFusion 11 to make it do the conversion like ColdFusion 9 did? Or will I have to fix this code, along with probably lots of other similar examples throughout the application? Neither I nor our ColdFusion administrator has been able to find any information about this in the ColdFusion Administrator interface, the ColdFusion documentation, or online.
Edit in Response to Adam Cameron in comments
I have created a file that consists of the following 10 lines (and nothing else):
<cfset VARIABLES.roleTypeId = false >
<cfoutput>
<p>#rolesForStudy( 1, VARIABLES.roleTypeId )#</p>
</cfoutput>
<cffunction name="rolesForStudy" >
<cfargument name="id" hint="Study Id">
<cfargument name="roleTypeId" default="#VARIABLES.roleTypeId#" type="numeric"/>
<cfreturn "It worked" >
</cffunction>
When I execute it in ColdFusion 9, it displays the words "It worked".
when I execute it in ColdFusion 11, it returns the following error message:
If the component name is specified as a type of this argument, it is possible that either a definition file for the component cannot be found or is not accessible.

I believe you will have to fix the code. There are no settings (that I know of at any rate) that alter the way CF handles boolean types. You should be able to change the assignement above from "false" to 0 and your function code will work. However I suspect elsewhere you might have something like <cfif variables.roletypeID IS "False"> which will then be broken as it is in truth looking for a string - which also works (ha). CF's handling of a myriad of values as boolean (0 or not 0, true, false, yes and no) is a legacy of it's origin. It's convenient at times but definitely leads to things like this.
Meanwhile I wonder if this change of behavior is a new bug or the fixing of an old bug. In my view passing "false" as an argument and having it read as numeric seems inconsistent so the new way of doing it seems right to me. However, many many languages treat 0 or not 0 as default values for true and false.
EDIT:
According to Adam's comments below, my example of code where someone would say:
<cfif somevar IS "false">
...would work even if somevar was indeed numeric. His example (useful) is that:
#0 is "False"#
...will output "yes" - so CF is recasting the string "false" to a zero under the hood for comparison. That makes my example incorrect.
My answer is still correct I believe. The issue he's running into is that the argument passed to his function - being of the type "boolean" is throwing an error because the function expects a numeric value. But Adam's point and example makes me think perhaps this behavior is a bug - since it appears CF is not casting to a number before checkign the type (something it did do in CF 9 according to the Joe).

NumberFormat is your saviour, credit going to this comment on one of Ben Nadel's articles.
<cfset VARIABLES.roleTypeId = false>
#NumberFormat(VARIABLES.roleTypeId)# <!-- = 0 -->
<cfset VARIABLES.roleTypeId = true>
#NumberFormat(VARIABLES.roleTypeId)# <!-- = 1 -->
So you should be able to either convert it to the expected numeric type before calling the function, or just doing
<cfargument name="roleTypeId" default="#NumberFormat(VARIABLES.roleTypeId)#" type="numeric">

I've raised this as a bug in ColdFusion 11: "Type coercion failure when passing boolean to a numeric arg".
I recommend you work around this by taking the type check off the argument. This is probably the lowest-impact fix.
This is also a rare case in which I'd add a comment to code, explaining why you've taken the type checking off.
Apologies to Joe, Mark & Duncan for emphatically contradicting what they were finding. That said, I don't agree that their answers are the best approach here ;-)

Related

Coldfusion: How to dump out arguments scope with cfthrow?

After my form submits I am calling a controller method that runs an orm EntitySave in my cfc. I would like to dump out the arguments before I save my data via ORM just to visually validate those are indeed the values I want to save in the database.
So when I use this
<cfthrow message="value = #arguments#">
I am getting this:
Error: Complex object types cannot be converted to simple values.
I understand you are not allowed to do this with complex objects, so in those cases I would use <cfdump> but I can't find a way to dump in a <cfthrow>. I am sure there is a better way to accomplish this. I have also tried doing a <cfmail> to myself which works amazingly but the email will take a minute or two. Any suggestions would be greatly appreciated. I am currently checking into ValidateThis.
You could serialise it:
<cfthrow message="value = #serializeJson(arguments)#">
But I don't think you want that sort of thing showing up on the screen.
I'd log it if I was you (so same notion, just <cflog> before the <cfthrow>, and put the arguments in the log entry, and in the <cfthrow> just put a brief explanation of the error (you should also use a TYPE attribute, for subsequent handling of the exception that you've raised.
Rather than throwing it, you could try dumping it to a file and see if that meets your needs:
<cfdump var="#arguments#" output="C:\dump.html" format="html">
If you need to abort (as a throw would do), you can add abort on to the end of the tag, <cfdump... abort>.
You could do the following in order to use <cfdump>:
<cfsavecontent variable="arguments_dump">
<cfdump var="#arguments#" />
</cfsavecontent>
<cfthrow message="#arguments_dump#" />
Takes a little bit more code however and is not as elegant as Adam Cameron's answer above.

How to properly use Coldfusion's FileExist() method?

I don't use coldfusion much at all, I'm needed to patch up some code though. Basically I'm trying to check and see if a file I uploaded exist and if it does exist, increment a variable by 1. Then repeat untill I get a unique file name. For whatever reason I can't figure out the proper way to use FileExist(). Some forums suggest using it with len() but those are from 2006 and when I do that it seems to always come out true. Also, when I look at http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7c66.html it says it returns either Yes or No. I tried to check against the result various ways, but no luck.
This is the portion of code I have which I am dealing with. The application.filepath is just a variable in my application file which store the expandpath().
<cffile action="upload" destination="#Application.filePath#ListingsGallery/" filefield="iconImage" nameconflict="makeunique">
<cfset iconPlace = #cffile.serverfile#>
<cfset myExt = listLast(iconPlace,".")>
<cfset i = 1 >
<cfset myVar = false>
<cfloop condition="myVar EQ false">
<cfset newIconName = "iconPhoto" & i &"."& myExt>
<cfset iconName = Application.filePath & "ListingsGallery/" & #newIconName#>
<cfoutput>#iconName#</cfoutput><br />//just checking to see if it is the correct path, it is.
<cfif FileExists(iconName) EQ 'Yes'>
<cfoutput>#myVar#</cfoutput> //checking the value, it never hits here.
<cfelse>
<cfoutput>#myVar#</cfoutput><br /> //checking the value, it always hits here.
<cfset myVar = true>
<cfoutput>#myVar#</cfoutput> //Again check the value.
</cfif>
<cfset i++>
</cfloop>
<cffile action="rename" source="#Application.filePath#ListingsGallery/#iconPlace#" destination="#Application.filePath#ListingsGallery/#newIconName#">
The absolute path on a unix server is something like, /var/www/website folder name/ etc....
Correct? That's the absolute server path, the coldfusion docs seem to specify at least a microsoft absolute server path so I'm assuming this is what is needed.
Edit---------------------------
PS: I can' only give one of you credit, so I gave it to Kruger since he came a minute earlier.
lol...
FileExists() returns a boolean value. This should work fine now that the typo has been fixed:
<cfif fileExists(TheFile)>
// do this
<cfelse>
// do that
</cfif>
Assuming your application.Filepath is the correct file path you are on the right track. It looks like your upload directory might be beneath the web root - considering moving it outside the web root for security. Take a look at #expandPath('.')# as a way of creating guaranteed file paths without typos :) Also makes your code more portable.
To my eye the code above would work. FYI - you don't need "EQ 'YES'. You are fine to just do:
<Cfif FileExists(iconName)>...
You could also do
condition="NOT myVar">
There are several ways to handle logic code in CF.
If your fileExists() never hits take a closer look at your rename. Are you throwing an eror?
I can't add notes to answers yet, but I wanted to let the OP know that CF is typeless when it comes to boolean evaluations in functions. 0 is the same as "no" is the same as "false", whereas any positive number is the same as "yes" is the same as "true".
Its great to have back-end security, but this should have been handled on the front-end so you never get values you don't want. The new HTML5 input patterns would prevent this from ever being submitted, so you wouldn't have to fix this on the back end.
http://www.w3schools.com/tags/att_input_pattern.asp

Getting "The format method was not found" when trying to use java.lang.string format method from ColdFusion

I want to do something in ColdFusion that is similar to sprintf in C or Perl. I found this
answer, which seems to be what I'm looking for. However, I can't get it to work.
Here is what I'm trying:
<cftry>
<cfset firstName="John">
<cfset output=createObject("java","java.lang.String").format("Hello, %s!", firstName)>
<cfcatch type="any">
<cfdump var="#cfcatch#" expand="false">
</cfcatch>
<cftry>
And here is what I get:
cfcatch.Message: The format method was not found.
cfcatch.Detail: Either there are no methods with the specified method
name and argument types or the format method is overloaded with
argument types that ColdFusion cannot decipher reliably. ColdFusion
found 0 methods that match the provided arguments. If this is a Java
object and you verified that the method exists, use the javacast
function to reduce ambiguity.
This is an overloaded method, so I did as suggested and used JavaCast on the arguments:
<cfset output=createObject("java","java.lang.String").format(JavaCast('string', "Hello, %s!"), firstName)>
<cfset output=createObject("java","java.lang.String").format("Hello, %s!", JavaCast('string', firstName))>
<cfset output=createObject("java","java.lang.String").format(JavaCast('string', "Hello, %s!"), JavaCast('string', firstName))>
and got the same error every time.
I tried another static method on the String class, valueOf, and it worked fine.
Edit:
I've already seen a comment, and I'm not sure how to respond to those, but maybe I should explain here. What I've shown above is an extremely simplified example of what I am trying to do. The goal is to use a format string to provide lots of formatting in one place, and then simply pass in a list of variables, instead of formatting a bunch of variables and outputting them, or formatting them as I'm outputting them. With the format method, I plan to build a set of format strings that match the output I need, then I will just cfloop or cfoutput over a query, run this one method inside, and get the output I want. No DateFormat, NumberFormat, Left, Right, etc. If I can't get this working, that is plan B though.
I'm running ColdFusion 9.01, Windows 7, Java 1.6.0_22.
Any and all help is greatly appreciated.
Answer based on my comment above:
It probably can't match the format method you're looking for because its signature is format(String, Object[]) and your second String argument can't be automatically converted to an Object array.
You could change the argument to encapsulate the name in an array as follows: format("Hello, %s!", [firstName]).
Thanks to Leigh for being so courteous, I upvoted your comments :)

Change to OnRequestEnd behavior in CF9 (was ColdFusion 9 Bug - Can't Reference a Request Variable in OnRequestEnd)

Here's a weird one. I haven't had any luck finding any information about this on Google, so I'm wondering if any of you have seen this before?
I've got a CFC in the request scope and then in the onRequestEnd event I grab that CFC out of the request scope and do some end-of-request stuff with it. The problem is I can't reference the variable in my onRequestEnd event because it produces an error that says it's not defined in the scope... but here's where it gets really weird and why I KNOW this is a bug (it's not just a suspicion)... If I DUMP the variable, the cfdump tag successfully displays the CFC and all its stuff... and then produces the same "is undefined in scope" error. Here's a screen-capture.
So... anybody seen this before? 'Cause I'm totally stumped. I've already installed the 9.0.1 updater and both of the cumulative hot fixes.
p.s. Yeah, I know it says OnRequestEnd.cfm, but this is actually inside the Application.cfc onRequestEnd method -- it's a legacy from the framework dating back originally to CF5, just go with it. ;P
EDIT: Okay, it's gotten weirder... I tried using evaluate() to set it to a local variable, which apparently works, because then I dump the local variable. The dump still works, even though it's on line 2 AFTER the line on which the error occurred?!!
EDIT 2: EDIT: Here's the code from the Application.cfc that includes the file where the error occurs:
<cffunction name="onRequestEnd" access="public" output="true">
<cfinclude template="OnRequestEnd.cfm">
</cffunction>
It appears to have something to do with the combination of the method and the include file.
It still fails if I execute the method in the onRequestStart like this:
<cffunction name="onRequestStart" access="public" output="true">
<cfset onRequestEnd() />
</cffunction>
But it works fine if I include the file in onRequestStart like this.
<cffunction name="onRequestStart" access="public" output="true">
<cfinclude template="OnRequestEnd.cfm">
</cffunction>
HOWEVER! There's obviously more to this because I can't create a simple test case. If I create a new project with a very simple application.cfc in it and replicate all these details, it works fine. So there's something else in the framework that's contributing to it beyond just the method names and file names.
And the file name doesn't seem to actually contribute, since it still fails in the same way if I change the name of the file like this:
<cffunction name="onRequestEnd" access="public" output="true">
<cfinclude template="reqend.cfm">
</cffunction>
EDIT 3: Okay it has nothing to do with the file... well it does, but not with the file name... At the bottom of the onRequestEnd.cfm is this code
<!--- this seems to help resolve a leaky-memory issue in CF/JRun --->
<cfset structClear(variables) />
<cfset structClear(request) />
<cfabort />
If I comment out those StructClear statements, then the error goes away, which told me that it was executing the OnRequestEnd.cfm twice... and I THINK that means that CF9 changed the behavior of the CFABORT tag and it now executes the onRequestEnd event when the tag is used... it didn't in previous versions of cf...
I didn't find documentation of this, but I did find this blog from Ben Nadel about this behavior with the CFLOCATION tag, so it seems to be more generally about the onRequestEnd event. It seems now in CF9, no matter how a page finishes executing, the onRequestEnd event is executed at the end... That's a change from all the previous versions and so it mucks with code I had created in order to actually cause this to happen on previous versions. Since I was causing execution of the onRequestEnd and then aborting the page early, CF now executes the onRequestEnd, aborts and then executes the onRequestEnd again because of the abort.
Luckily, this fairly simple bit of code at the top of the template seems to fix the problem:
<cfif structIsEmpty(request)>
<cfexit method="exittemplate" />
</cfif>
I decided to leave this question here (rather than deleting it) since it may help some other folks, though I found the source of the problem and a workaround while working with some of the comments and it wasn't what we thought. Ben Nadel also posted a blog about the change to CFABORT a while ago as well... and Adam Cameron tells me that although this change was added by-design in CF9 (without warning anyone apparently, since I saw no mention in the LiveDocs and added 2 comments about it), it was then removed in the (not yet released?) CF10. I think Adam might be in the beta, I'm not sure.

Is output=false by default for cfscript function in CFC?

I thought CFC's methods defined as functions in cfscript are output=false by default, but when I open the CFC in cfcexplorer.cfc (browser directly to the CFC), it says Output: enabled.
cfcexplorer.cfc's Bug?
Short answer:
It doesn't matter.
cfscript does not output anything unless you explicitly call writeOutput() from it. This includes functions in cfscript as well as any cfscript code outside of a function.
This is different from CF tags' syntax, which, by default, output at least whitespace between the tags. In cfscript, any text you write will be compiled by the CFML engine. in CF tags, any text you write will be written to the output buffer and sent to browser.
Long answer:
It's the same as not specifying an output attribute.
cfscript blocks don't output anything. Any tag blocks, unless wrapped in cfsilent, do output whitespace if nothing else. Yes, even cffunctions do, but the output is discarded if the output attribute is set to false.
The essence of Peter Boughton's answer is correct. It's neither wrapped in cfsilent nor cfoutput. Output is not forbidden, but it doesn't happen unless you do it explicitly.
You can always combine a tag-based cffunction with scripting to get the best of both worlds. Something like...
<cffunction name="x" output="false" access="package">
<cfargument name="y" type="string" required="false" default="YY" />
<cfscript>
var someValue = y & "something";
writeOutput("test"); // this will not be written
return someValue;
</cfscript>
</cffunction>
This lets you specify an output and access on the cffunction tag as well as allow arguments to be optional (which you can't do through cfscript functions), then fill the body with cfscript, including var statements and the function return.
Of course, for that function, if you remove the output attribute or change it to true, it will output "test" before returning.
cfscript functions are a weird monkey. They are kind of both. You can't specify that they are output="false", but they are until you use a writeOutput(), but they are reported by cfcexplorer as being output="true". It is an odd issue I think the cfml advisory committee is looking at right now.
I'm not entirely certain, but my guess would be that script functions are the same as cffunction tags in this regard - in that the default is neither true nor false.
Setting the output attribute for a cffunction, the following are the case:
true is equivalent to the function being wrapped in cfoutput.
false is equivalent to the function being wrapped in cfsilent.
Leaving it default (undefined) is equivalent to standard code that is wrapped neither with cfoutput nor cfsilent.
However, I almost never use cfscript, and this may not actually be the case - we'll have to wait for others to come along and either confirm or correct this.