Gotchas with Groovy Exceptions
Posted by jt - 08/03/11 at 02:03 pmI ran into a little gotcha with Groovy exceptions today. I seemed like my catch block was not catching the exception type I was throwing in my code.
Lets say I’ve defined my own exception as
class NotFoundException extends Exception { } |
And I have a method call as:
def getApplication(def params) { def application = Application.get(params?.id) if (!application) { throw new NotFoundException() } application } |
In my case this the above is a method in a service which is injected into a Grails controller. In my controller, I want to handle any exceptions that pop, rather than going boom to the web tier. My controller code looks something like this:
def approve = { def returnMap = [:] returnMap.success = true try { def application = applicationService.approve(params) returnMap.message = "Application for ${application.firstName} ${application.lastName} has been approved." } catch (NotFoundException e) { returnMap.success = false returnMap.message = 'Application not found.' log.error("Failed to find application") log.error(params.dump()) } catch (e) { returnMap.success = false returnMap.message = 'Error updating application. See logs for details' log.error("Failed to find application") log.error(e) log.error(e.cause) e.stackTrace.each { log.error(it) } } render returnMap as JSON } |
I want the above code catch the error and provide sometime of informational message to the client by setting the returnMap.message property.
The problem I encountered in my catch block was that it was always falling through to the final catch block. The catch block for the NotFoundExcpetion was getting skipped.
Turns out, the exception was getting thrown as a “UndeclaredThrowableException” and not a NotFoundException. Since the types did not match, my catch block was getting skipped.
The solution to this is to declare the exception on your method. Then the exception will propagate properly. I guess its the price you have to pay for the Groovyness of Groovy.
The corrected code (note the throws declaration) :
def getApplication(def params) throws NotFoundException { def application = Application.get(params?.id) if (!application) { throw new NotFoundException() } application } |
A bunch of random technology stuff that has my attention. I work with a lot of Oracle, Java, and dabble with various open source software packages.
March 8th, 2011 at 2:29 pm
FYI if you want to deal with UndeclaredThrowableException remember that the underlying exception will be in UndeclaredThrowableException.undeclaredThrowable
e.g
try {
//…
} catch (e) {
Throwable t = e instanceof UndeclaredThrowableException ? e.undeclaredThrowable : e
//…
}
March 8th, 2011 at 2:32 pm
[...] I’ve defined my own exception as class NotFoundException extends Exception { }… [full post] jt JT's Blog uncategorized 0 0 0 0 0 [08 Mar [...]
March 8th, 2011 at 3:45 pm
Thanks – I did see that in the API… Less code to refactor by adding ‘throws…’ (since I already had the catches coded)
July 8th, 2011 at 2:50 pm
Are you sure this is groovy’s fault? I think spring’s proxy is the one to blame here.
July 9th, 2011 at 7:41 am
Yes, its a behavior of Groovy. If you don’t declare the ‘throws’ in your method signature, it is raised as a Undeclared exception.
November 27th, 2011 at 10:34 am
If you extend RuntimeException (instead of Exception), you don’t need to specify what is throwing on the method’s signature since RuntimeException is an unchecked exception and maybe your first example would throw the right exception.