Over a million developers have joined DZone.

Good Use of Closures

· DevOps Zone

Discover how to optimize your DevOps workflows with our cloud-based automated testing infrastructure, brought to you in partnership with Sauce Labs

Not long ago, in a blog post, I explained what Closure were in Groovy.  This blog post will explain one good example of using them.  I recently found myself having to write the same exception handling logic for a bunch of back-end Controller APIs which were serving AJAX requests.  It was like this

class ApiRugbyPlayerController {
JSON getPlayerStats() {
try {
...
// invoke business service method to get player stats
} catch (ServiceException serviceException) {
// don't care too much about this.
// log and move on
... 
} catch (SessionException sessionException) {
// clear out session cookies
...
// send 403 to client
...
} catch (Exception ex) {
throw new ApiException(ex)
}
}
JSON updatePlayerStats() {
try {
...
// invoke business service method to update player stats
} catch (ServiceException serviceException) {
// don't care too much about this.
// log and move on
... 
} catch (SessionException sessionException) {
// clear out session cookies
...
// send 403 to client
...
} catch (Exception ex) {
throw new ApiException(ex)
}
}
JSON queryPlayerStats(){
try {
...
// invoke business service method to query player stats
} catch (ServiceException serviceException) {
// don't care too much about this.
// log and move on
... 
} catch (SessionException sessionException) {
// clear out session cookies
...
// send 403 to client
...
} catch (Exception ex) {
throw new ApiException(ex)
}
}
}

As can be seen, there is some code duplication going on here. In the spirit of DRY (don't repeat yourself), it is better to only define this exception handling logic once and then re-use it. So I defined the following utility method, which implements the exception handling pattern and takes a closure which is executes the exception handling for.

private JSON withExceptionHandling(Closure c) {
try {
...
c.call();
} catch (ServiceException serviceException) {
// don't care too much about this.
// log and move on
... 
} catch (SessionException sessionException) {
// clear out session cookies
...
// send 403 to client
...
} catch (Exception ex) {
throw new ApiException(ex)
}
}

We can make a code block a closure in Groovy by surrounding it with {}. This means I can make the logic inside my Controller methods into Closures and pass them to my utility method. And when I pass it to my utility method I don't even need to pass it inside a () as Groovy doesn't make you. So that means, I can take out all the common exception handling, remove the code bloat and my Controller API's are much cleaner.

class ApiRugbyPlayerController {
JSON getPlayerStats() {
withExceptionHandling {
...
// invoke business service method to get player stats
}
}
JSON updatePlayerStats() {
withExceptionHandling {
...
// invoke business service method to update player stats
}
}
JSON queryPlayerStats(){
withExceptionHandling {
...
// invoke business service method to query player stats
}
}
private JSON withExceptionHandling(Closure c) {
try {
...
c.call();
} catch (ServiceException serviceException) {
// don't care too much about this.
// log and move on
... 
} catch (SessionException sessionException) {
// clear out session cookies
...
// send 403 to client
...
} catch (Exception ex) {
throw new ApiException(ex)
}
}
}

So there we go. We have adhered to DRY principles, avoided code bloat and have a dedicated place for our exception handling confident that it being implemented consistently. This example of Groovy closure is a little but like a second order invocation in JavaScript. If we wanted to do something like in Java, it would just involve a lot more code. We could use something like the command pattern and put the execution of them into the exception handling logic. You would have more decoupling, but you have a lot more code. Or you could make all your AJAX APIs enter a common method (like a Front Controller) and but your common exception handling there. Again, possible but just more code. Until the next time, take care of yourselves.

Download “The DevOps Journey - From Waterfall to Continuous Delivery” to learn learn about the importance of integrating automated testing into the DevOps workflow, brought to you in partnership with Sauce Labs.

Topics:

Published at DZone with permission of Alex Staveley, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}