Update:
I had to take this article down for a few hours as I ballsed up both the code and the analysis! Thanks to Adam Tuttle for noticing (or making me revisit it so I noticed it, anyhow).It pleases me when I learn something I didn't know about fundamental parts of CFML. I temporarily feel daft, but I'm used to that.
Ray - amidst a fiery exchange of disagreement last night - set me straight on a feature of CFML's exception-handling that I was completely unaware of. Despite it being well documented. Since ColdFusion 4.5. Cool!
I had never noticed this from the
<cfcatch>
docs:The custom_type type is a developer-defined type specified in a cfthrow tag. If you define a custom type as a series of strings concatenated by periods (for example, "MyApp.BusinessRuleException.InvalidAccount"), ColdFusion can catch the custom type by its character pattern. ColdFusion searches for a cfcatch tag in the cftryblock with a matching exception type, starting with the most specific (the entire string), and ending with the least specific.The "funny" (at my expense) thing here is that not only did I not know that, I had actually wanted
<cfcatch>
to work that way, and just ass-u-me`d it didn't so never tried it! Fuckwit.Here's an example:
// hierarchicalExceptions.cfm
param URL.type;
try {
writeOutput(htmlEditFormat("<code>Throwing a <strong>#URL.type#</strong> exception<br>"));
throw(type=URL.type);
}catch (com.theapplication.thepackage.TheComponent.TheException e) {
message = "name-spaced exception";
}catch (com.theapplication.thepackage.TheComponent e) {
message = "component";
}catch (com.theapplication.thepackage e){
message = "package";
}catch (com.theapplication e){
message = "application";
}catch(any e){
message = "default";
}
writeOutput(htmlEditFormat("The <strong>#URL.type#</strong> exception was caught by the <strong>#message#</strong> exception handler<br></code><hr>"));
Here we can pass various different exception types to throw, and check where they "land". These are a number of tests using Railo:
Throwing a AnyOldException exception
The AnyOldException exception was caught by the default exception handler
This is correct, if not at all exciting: we don't have a pattern that catches this, so it falls through to the default.
Throwing a com.theapplication exception
The com.theapplication exception was caught by the application exception handler
This also doesn't demonstrate much:
com.theapplication
is an exact match of one of the catch
conditions. But it works.
Throwing a com.theapplication.differentpackage exception
The com.theapplication.differentpackage exception was caught by the application exception handler
Now we get down to business, and the technique is demonstrated: the thrown exception -
com.theapplication.differentpackage
- has no exact match in any of the catch
conditions, but it's still matched by the "namespace" of com.theapplication
catch
condition. Excellent!
Throwing a com.theapplication.thepackage exception
The com.theapplication.thepackage exception was caught by the package exception handler
No surprises here: it's an exact match.
Throwing a com.theapplication.thepackage.DifferentComponent exception
The com.theapplication.thepackage.DifferentComponent exception was caught by the package exception handler
Here we have a different component, but the path is otherwise the same, so it gets picked up by the
package
catch
condition
Throwing a com.theapplication.thepackage.TheComponent exception
The com.theapplication.thepackage.TheComponent exception was caught by the component exception handler
We're in the realm of "doing this for completeness" now. Everything is still working as expected.
Throwing a com.theapplication.thepackage.TheComponent.DifferentException exception
The com.theapplication.thepackage.TheComponent.DifferentException exception was caught by the component exception handler
A different exception from the same component gets picked up by the
component
handler.
Throwing a com.theapplication.thepackage.TheComponent.TheException exception
The com.theapplication.thepackage.TheComponent.TheException exception was caught by the name-spaced exception exception handler
More of the same. Just one more...
Throwing a TheException exception
The TheException exception was caught by the default exception handler
This demonstrates that the "namespace" on the exception is significant. A
TheException
exception is different from a com.theapplication.thepackage.TheComponent.TheException
So that's quite cool.
And ColdFusion 11 works the same way (I have no reason to think any earlier version does not, that's just what I tested on).
Did you know you could do this?
Righto.
--
Adam