ColdFusion MX added try/catch to the CFSCRIPT, a welcome addition, but you can't throw an exception, or rethrow. Doing a throw is quite easy if you write a UDF for it. However, rethrow is not so easy. You may think:
<cfrethrow>
</cffunction>
However, this will cause a syntax error since rethrow must be contained inside a cfcatch block. For the heck of it, I tried the following:
<cftry>
<cfcatch>
<cfrethrow>
</cfcatch>
</cftry>
</cffunction>
<cftry>
<cfscript>
try {
throw("my type","my ex");
} catch(Exception e) {
rethrow();
}
</cfscript>
<cfcatch>
<cfoutput>exception thrown</cfoutput>
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
What surprised me is that my rethrow UDF noticed an error had occured and automatically entered the cfcatch block.
This had one problem though. I could call rethrow outside of cfcatch. It wouldn't throw an exception, it would simply do nothing. I modified the UDF like so:
<cftry>
<cfcatch>
<cfrethrow>
</cfcatch>
</cftry>
<cfthrow type="Context validation error" message="Context validation error for CFRETHROW.">
</cffunction>
You will only get to the end of the UDF when you haven't called rethrow() in a catch block.
p.s. Normally I'd add returnType/output/etc to my code. Don't forget to do so if you actually use the UDFs.
p.s.s. And of course, I'd much prefer it if MACR would simply add throw/rethrow to cfscript. :)
Archived Comments
"p.s.s. And of course, I'd much prefer it if MACR would simply add throw/rethrow to cfscript. :)"
I would prefer a full cfscript implementation of cfml tags.
Sure tag based syntax is good, and i love it, but for the presentation layer ... i really would prefer a script based syntax for the business layer ( much like the Flex programming model ).
Next xmas i'll send this gift request to santa ..
Please please macromedia, give cf a nice programming model like his brother flex !
One thing that should be clarified is that this rethrow() function needs to be called within a CFTRY block--simply being within a cfscript try{} block isn't enough.
For example, the following code will not work (rethrow() throws a "Context validation error"):
<pre>
<cfscript>
try {
try {
throw('foo', 'bar');
} catch (foo e) {
rethrow(); // error here
}
WriteOutput("rethrow() didn't work");
} catch (foo e) {
WriteOutput("rethrow() worked");
}
<cfscript>
</pre>
While the following code does work:
<pre>
<cftry>
<cfscript>
try {
throw('foo', 'bar');
} catch (foo e) {
rethrow();
}
WriteOutput("rethrow() didn't work");
</cfscript>
<cfcatch type="foo">
<cfoutput "rethrow() worked">
</cftry>
</pre>
That sure did look ugly... Let's try that comment again:
----------
One thing that should be clarified is that this rethrow() function needs to be called within a CFTRY block--simply being within a cfscript try{} block isn't enough.
For example, the following code will not work (rethrow() throws a "Context validation error"):
<cfscript>
try {
try {
throw('foo', 'bar');
} catch (foo e) {
rethrow(); // error here
}
WriteOutput("rethrow() didn't work");
} catch (foo e) {
WriteOutput("rethrow() worked");
}
<cfscript>
While the following code does work:
<cftry>
<cfscript>
try {
throw('foo', 'bar');
} catch (foo e) {
rethrow(); }
WriteOutput("rethrow() didn't work");
</cfscript>
<cfcatch type="foo">
<cfoutput "rethrow() worked">
</cftry>
Sorry for necroposting...
I was disappointed that throw() and rethrow() weren't included in the CF MX updater 7.01.
Here are my versions of throw() and rethrow():
<cfcomponent displayname="allErrorHandling">
<cffunction name="throw" access="public" returntype="void" hint="Call throw() with named arguments, rather than positional. While all arguments are optional, the message and detail argments are strongly recommended. The object paramter of CFTHROW is not supported.">
<cfargument name="message" type="string" required="false" default="">
<cfargument name="detail" type="string" required="false" default="">
<cfargument name="errorcode" type="string" required="false" default="">
<cfargument name="extendedinfo" type="string" required="false" default="">
<cfargument name="type" type="string" required="false">
<cfif StructKeyExists(arguments, "object")>
<cfthrow detail="#arguments.detail#" errorcode="#arguments.errorcode#" extendedinfo="#arguments.extendedinfo#" message="#arguments.message#" type="#arguments.type#">
<cfelse>
<cfthrow detail="#arguments.detail#" errorcode="#arguments.errorcode#" extendedinfo="#arguments.extendedinfo#" message="#arguments.message#">
</cfif>
</cffunction>
<cffunction name="rethrow" access="public" returntype="void" hint="Use this only inside catch blocks in CFSCRIPT. Unlike CFRETHROW, you must feed in the exception being rethrown. Only the message, detail, errorcode, extendedinfo, and type keys of the exception structure will be rethrown, but it's better than nothing.">
<cfargument name="exception" type="struct" required="yes" hint="Any exception structure from a catch block in CFSCRIPT.">
<cfscript>
if (not StructKeyExists(exception, "message")) {
exception["message"] = "";
}
if (not StructKeyExists(exception, "detail")) {
exception["detail"] = "";
}
if (not StructKeyExists(exception, "errorcode")) {
exception["errorcode"] = "";
}
if (not StructKeyExists(exception, "extendedinfo")) {
exception["extendedinfo"] = "";
}
if (StructKeyExists(exception, "type")) {
throw(exception.message, exception.detail, exception.errorcode, exception.extendedinfo, exception.type);
} else {
throw(exception.message, exception.detail, exception.errorcode, exception.extendedinfo);
}
</cfscript>
</cffunction>
</cfcomponent>
Ray, I notice you haven't added this to cflib. Is there something missing that's caused that? I'm doing an article in the CFDJ on error handling and am pointing to your throw UDF. If you might be adding this one, I'd point to it also.
Released, http://www.cflib.org/udf.cf....
Great, thanks, and duly noted in the article. Cheers.
Done... ColdFusion 9 has throw/rethrow in CFSCRIPT. Booyah!
Ps. You're welcome. ;-)
Call me crazy, but wouldn't the following work as a rethrow?
try
{
...
}
catch(Any e)
{
throw(ArgumentCollection = e);
}
Did you try it? ;)
Just Tried it, didn't work.
However, putting:
Throw(object = e);
does rethrow your error.