1
\$\begingroup\$

My code has a nasty smell that looks like this:

@RequestMapping(value = { "/updateGraph" }, method = RequestMethod.POST)
public ResponseEntity<ArrowsGraph> updateGraph(@RequestBody ArrowsGraph g){
    try{
        g = arrowsBo.updateGraph(g);            
        return new ResponseEntity<ArrowsGraph>(g, HttpStatus.OK);
    } catch (Exception e) {
        errorLogging.logFatalException(e,  sessionState);
        return new ResponseEntity<ArrowsGraph>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

@RequestMapping(value = { "/deleteGraph" }, method = RequestMethod.POST)
public ResponseEntity<ArrowsGraph>  deleteGraph(@RequestBody ArrowsGraph g){
    try{
        g = arrowsBo.deleteGraph(g);
        return new ResponseEntity<ArrowsGraph>(g, HttpStatus.OK);
    } catch (Exception e) {
        errorLogging.logFatalException(e,  sessionState);
        return new ResponseEntity<ArrowsGraph>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

Things to mention:

  • The exceptions being caught are runtime exceptions, likely thrown if the database mapping is configured incorrectly. If the code is working correctly, exceptions should never be thrown, but in the case there is an error, I want to display an error the client side, instead of having unintended behaviour.
  • The reason I'm using ResponseEntity<..> instead of @ResponseBody is so I can return a 500 in the case that an exception is thrown.
  • The purpose of errorLogging.logFatalException(...) is to log the error, and notify admins.

Before I refactored to use ResponseEntity<...> and catch the runtime exceptions, the methods looked a lot cleaner:

@RequestMapping(value = { "/deleteGraph" }, method = RequestMethod.POST)
public ArrowsGraph  deleteGraph(@RequestBody ArrowsGraph )
     return arrowsBo.deleteGraph(g);
}

Is there a nice way to avoid this repetition/boilerplate?

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Is there a nice way to avoid this repetition/boilerplate?

Yes, there is a cleaner way.

Since you are using Spring, please check the annotation @ControllerAdvice and the class ResponseEntityExceptionHandler.

To handle exceptions, you'll need to extend ResponseEntityExceptionHandler and manage the returned ResponseEntity in a method annotated with @ExceptionHandler, for example:

@ControllerAdvice(basePackageClasses = MyControllerClass.class)
public class ErrorResponseHandler extends ResponseEntityExceptionHandler {

  @ExceptionHandler(MyExceptionType.class)
  @ResponseBody
  ResponseEntity<Object> handleControllerException(HttpServletRequest request, Throwable ex) {
    // process the exception and wrap the response to return in ResponseEntity
  }

}

Using this approach, you service methods will remain one-liners, returning non-wrapped ArrowsGraph instances.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This is what I do in my projects. Additionally, I put the desired HTTPStatusCode in my custom Exception. I also check whether X-Requested-With: XMLHttpRequest to return a JSON formatted error, if not I return an HTML error page: This might be problematic in combination with an api for a public audience that should never return HTML though. \$\endgroup\$
    – ASA
    Jun 2, 2016 at 12:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.