Modifying the message in a CFCATCH before rethrowing error

Posted by Dan on May 26, 2011 @ 10:58 AM

This morning I was working on some code where I wanted to capture an error in side a cftry/cfcatch block and rethrow the message, but I wanted to modify the cfcatch.message key to include more detail without losing the stack trace. I could have just used the <cfthrow /> tag and used the type, message and detail attributes but this would have caused me to lose the stack trace—which I needed.

Idealistically, I could have just modified the "message" key in the cfcatch variable, but the problem is the ColdFusion cfcatch variable is not really a struct—it looks like one—but it's actually an Java exception. Because it's not really a struct, it's not possible to just edit key values—making the cfcatch variable essentially read-only.

This got me looking into a method were I could rethrow the original stack trace, but customize the "message" key. After a few minutes playing around the java.lang.Exception object, I came up with the following:

  <cffunction name="rethrowMessage" access="public" returntype="void" output="false" hint="Rethrow a CFCATCH error, but allows customizing the message key">
    <cfargument name="cfcatch" type="any" required="true" />
    <cfargument name="message" type="string" required="false" />

    <cfset var exception = "" />

    <cfif not structKeyExists(arguments, "message")>
      <cfset arguments.message = arguments.cfcatch.message />
    </cfif>

    <cfset exception = createObject("java", "java.lang.Exception").init(arguments.message) />
    <cfset exception.initCause(arguments.cfcatch.getCause()) />
    <cfset exception.setStackTrace(arguments.cfcatch.getStackTrace()) />

    <cfthrow object="#exception#" />
  </cffunction>

Using this UDF, I can now do something like:

<cfscript>
  // connect and authenticate
   try {
    store.connect(variables.instance.server, variables.instance.username, variables.instance.password);
  } catch(Any e) {
    // throw original message, but append the username to the message
    rethrowMessage(cfcatch=e, message=e.Message & " [#variables.instance.username#]");
  }
</cfscript>

This allows me to throw the original Java error that occurs when connecting to a JavaMail Store occurs, but modify the message to include the mailbox I'm trying to connect to  which is helpful in debugging the root cause.

Categories: HTML/ColdFusion

3 Comments

  • Hmm, did you try AttributeCollection?

    <cfif isDefined('variables.instance.username')>
        <cfthrow
            message = "#cfcatch.message# [#variables.instance.username#]"
            attributecollection = #cfcatch#
        />
    <cfelse>
        <cfrethrow />
    </cfif>

    Haven't tested it, but would expect that to work.
  • @Peter:

    I didn't test that method, but CF throws errors when you try to use invalid attributes on the CFCATCH tag. Not all the keys in a CFCATCH are valid attributes.
  • Ah, so that's what the "object" attribute is for. Very cool!

Comments for this entry have been disabled.