Encapsulating Common Exceptions in ColdFusion

When throwing exceptions in ColdFusion, we have the mighty <cfthrow> tag, which allows us to throw exceptions, with given names, and then catch them elsewhere in our application.

For example:

<cftry>
   <cfthrow type="myException" message="This is my custom exception" detail="This is my custom exception detail"/>

   <cfcatch type="myException" />
      <cfset writeOutput("Caught Exception") />
   </cfcatch>
</cftry>


Would output 'Caught Exception' onto the screen, as the cfcatch 'type' matches the name of the Exception being thrown.

This is all very well and good for a 'once off' throwing of an
exception, but what happens when an Exception type is used across an
code base?  Often I have found myself copy and pasting <cfthrow> statements, just so I can have consistent types, messages and details between Exceptions within a system.

Taking inspiration for the way in which Java has actual Exception
objects, which can be implemented and then reused, I came up with the
following solution, which I felt was quite elegant, and extensible.

It all starts with a single, lowly Exception.cfc, that looks a little like this:


<cfcomponent name="Exception" hint="Throws a given exception" output="false">

<cffunction name="init" hint="Constructor" access="public" returntype="void" output="false">
    <cfargument name="message" hint="the message to throw" type="string" required="Yes">
    <cfargument name="detail" hint="the detail in which to throw" type="string" required="Yes">

    <cfthrow type="#getMetaData(this).name#" message="#arguments.message#" detail="#detail#">
</cffunction>

</cfcomponent>


..and while this doesn't look like much in and of itself, it becomes
quite useful when we start extending it, and using it create our own
Exception types, for example, we can rewrite the example above, as myException.cfc:

<cfcomponent name="myException" hint="Throws myException" extends="Exception" output="false">

<cffunction name="init" hint="Constructor" access="public" returntype="void" output="false">
   <cfset super.init("This is my custom exception", "This is my custom exception detail") />
</cffunction>

</cfcomponent>


To then throw myException, I simply do:

<cftry>
  
<cfset createObject("component", "myException").init();

   <cfcatch type="myException" />
      <cfset writeOutput("Caught Exception") />
   </cfcatch>
</cftry>

..and the exception will be thrown, with the type 'myException', which comes from the name of the CFC, without me having to write the same message, and detail over and over again.

To get more complicated, and to lift an example directly out of Conduit , this is the exception that gets thrown when Conduit can't find a particular method on a CFC it's making a Flex Remoting call to.

<cfcomponent name="MethodNotFoundException" hint="Exception for method not being found" extends="Exception" output="false">

<cffunction name="init" hint="Constructor" access="public" returntype="void" output="false">
    <cfargument name="component" hint="the component that the method is attempting to be called on" type="any" required="Yes">
    <cfargument name="methodName" hint="the name of the method" type="string" required="Yes">

    <cfscript>
        super.init("The method '#arguments.methodName#' in '#getMetaData(arguments.component).name#' could not be found.",
                    "This method could not be found. Please ensure that it was spelled correctly, and is not private"
                    );
    </cfscript>
</cffunction>

</cfcomponent>

In this case we take a component and a method name as an argument,
and
can build Exception messages and details, based on those arguments,
much like you can with Java Exceptions. However, the actual Exception
type in this example will actually end up being
'conduit.exceptions.MethodNotFoundException', as this CFC is found in
/conduit/exceptions/MethodNotFoundException.cfc.

Now that your Exceptions are encapsulated inside CFCs, you can use
them all over your code base, knowing the Exception type will not
change, and you don't have to copy and paste your messages and details
every time you want to use them.  There are other ways of doing similar
things, but this is one way I found works well for me.

Leave a Comment

Comments

  • Jason Dean | January 13, 2009

    Mark, thanks for posting this! I was trying to figure out a way to do something like this a few weeks ago. I put the project on hold since i could not figure it out in the time that I worked on it. This may be just what I was looking for.

    Would there be any reason not to use an object factory for this, instead of using createObject()? I suspect you were just keeping your example simple.

  • Mark | January 13, 2009

    @Jason,

    You’re welcome :D

    I don’t use an object factory when doing this, I just use createObject(). What benefit do you see in using an Object Factory?

  • Jason Dean | January 13, 2009

    I hate it when you ask those questions :) But you always do.

    Well one reason I can think of is so that I can move my exception CFCs around, like if I decide to share them across applications later.

    Also, for extending their functionality, like if I decide I also need a custom logger object in my exception CFCs.

  • Mark | January 13, 2009

    @Jason,

    Heh, I’m nothing if not predictable ;o)

    If you move them around, then the exception type will change, which may not be what you want. What I’ve done above is fairly close to how Exceptions work in Java.

    I don’t think Exception objects are places for complex logic, they really exist simply to be thrown, and for some other piece of code to catch them. If you are logging errors, it should be in the catching code, not in the throwing code.

  • Jason Dean | January 13, 2009

    That makes sense. Thanks for the discussion. I am looking forward to trying this out.

  • Rich Rein | January 14, 2009

    At the risk of sounding ungrateful, I do have a few comments that I hope are taken as constructive criticism…

    While I understand what you are trying to accomplish, I don’t like the fact that now an error condition has a CreateObject line instead of a throw. This is a bit difficult for me to swallow for a few reasons:

    1) It isn’t obvious in the code anymore what is going on there. We have all been conditioned from early on in our development careers that when you see a throw, it was because you hit a bad condition, and want to let something else know that. Now, a quick glance at the code no longer makes this obvious (yes, you do have the word Exception in the name of your CFC – but it still took me a minute or two of looking at your example to figure out what it was actually doing).

    Along those same lines, would it make more sense to do some of this processsing in the cfcatch? You could still throw a meaningful error, something like MyApp.Validation.BadEmail, and then pass that to a CFC to retrieve the global information (so that it is only defined once). I get that the intent is to reduce the number of times that you have to define things like the error message or error detail, I guess I just don’t like the idea of changing the way that we throw errors (you mention trying to mimic java behavior, but java still uses the throw statement for both built-in and custom error types).

    As for the comment about logging from within your exception (which provides probably cause for wrapping your exception calls behind something like ColdSpring), I think that Jason was spot on. Your actual code shouldn’t care if this type of message should get logged or not – it should just try to do its job, and then throw an exception when it can’t. At that point (separation of concerns), your exception logic can determine the next course of action – should I log this? should I email someone? should I just fail silently and let the calling template continue?

    Finally (and this is probably more of a nitpick), your example doesn’t show you using any of the information you create in the cfc. While the intent was probably to keep the example as basic as possible, it might make it a bit more obvious if you did something like WriteOutput("Caught something: #cfcatch.message#") to show that your CFC is really still just throwing an error, and that the detail/message attributes still have some meaning.

  • Mark | January 14, 2009

    @Rich,

    Re point: 1.
    I feel the ‘Exception’ part of the object lets me know what is going on. If you require a more explicit version of this, you could always rename the ‘init’ function to ‘throw’, so you could have:
    createObject("component", "myException").throw();

    Or even have a:

    exc = createObject("component", "myException").init();
    exc.throw();

    as a two step process. I figure a 2 step process is simply overkill as 9/10 times all you are doing is throwing as soon as you create the object, but if it makes you happy, so be it.

    Re: ‘Along those same lines, would it make more sense to do some of this processsing in the cfcatch?’ Which processing? I don’t follow you here? Are you saying the exception should be double handled in the catch? and then rethrown?

    Re: ‘As for the comment about logging from within your exception’, no I stand my ground on this one. Logging shouldn’t be done within the Exception itself, logging should be done by the code * handling * the Exception. It is the job of the catching code to decide what to do with the error, not the job of the Exception to tell the rest of the application what to do. That is separation of concerns.

  • Rich Rein | January 14, 2009

    @Mark-

    Well played. I will do my best to address your response in a way that hopefully keeps the points a bit better connected.

    We will have to agree to disagree I guess, as it still feels a bit clumsy to me to look for createObject() instead of throw(), although you have a valid point – the word "exception" is present in the name of your CFC, and you could just as easily use a throw() method on that cfc instead of init() for additional clarity.

    Tying that response in with my comment "would it make more sense to do some of this processsing in the cfcatch?", here is what I was thinking. By introducing a createObject() call instead of call to something like cfthrow, you are now additionally reliant on that component existing (or ColdFusion knowing where to find it, etc.), whereas if ColdFusion is running and processing the request, it always knows what to do with a cfthrow call. My thinking was something along the lines of this:
    try {
    throw("MyException");
    } catch MyException {
    createObject("component", "ExceptionHandler").init(cfcatch.type);
    }

    By doing your additional work in the catch portion (rather than when attempting to throw the error), you can still maintain a separate (and resuable) way of defining "expected" exceptions (i.e. my example of MyApp.Validation.BadEmail above), but the original code being executed is still just a cfthrow. In thinking through my original suggestion, this really has to be part of a more global-level error handler – because yes, I guess that really would be a second throw (ideally, up to a top-level handler that knew what to do with such errors in lower levels of the code). THinking along this line is what led me to think that the ExceptionHandler CFC would also determine (by exception type) what it should do with the error. I see your point (I think) – really the cfcatch block would be responsible for determing that, the ExceptionHandler would just deal with stuff like "for exception type x, use this message and this detail".

    All of that being said, I guess you really could go back to your original example (combined with something like ColdSpring, as Jason seemed to be suggesting), and really boil your throw code down to something like Application.ExceptionHandler.throw("MyException), which seems to satisfy my seemingly minor squabble and accomplishes what your example set out to accomplish :)

  • Bryon Reynolds | May 14, 2009

    This seems like a robust approach to defining exceptions in ColdFusion. It just looked a little weird, until I sat down and thought about it more.

    ColdFusion’s "createObject(‘component’,’path.to.MyCustomException’).throw()" is equivalent to Java’s "throw new MyCustomException;" – the parts are just switched around.