I have a Java EE application with dozens of web services using the same pattern:
public Response myWebService1() { try { // do something different depending on the web service called } catch (MyCustomException e1) { return Response.status(409).build(); } catch (UnauthorizedException e2) { return Response.status(401).build(); } catch (Exception e3) { return Response.status(500).build(); } }
Is that possible to factorize this piece of code?
It is perfectly fine to use two try/catch blocks if the algorithm requires it. I have often used a new try/catch in a catch block to ensure a safe cleanup so a blanket statement is not possible.
The try-catch statement consists of a try block followed by one or more catch clauses, which specify handlers for different exceptions. When an exception is thrown, the common language runtime (CLR) looks for the catch statement that handles this exception.
try/catch will only effect performance if an Exception is thrown (but that still isn't because of try/catch , it is because an Exception is being created). try/catch/finally does not add any additional overhead over try/catch .
From what I've read myself, the throws should be used when the caller has broken their end of the contract (passed object) and the try-catch should be used when an exception takes place during an operation that is being carried out inside the method.
If this is a JAX-RS environment, see Tunaki's answer, handling this is specifically catered for and wonderfully simple.
If not:
You can have a functional interface accepting a function that can throw exceptions and returns a Response
:
@FunctionalInterface public interface Responder { Response handleRequest() throws Exception; }
(As Dici points out, you could make that a generic ThrowingSupplier
or similar, since you're allowing it to throw Exception
.)
Then have a helper method accepting an instance of it:
private static Response respond(Responder responder) { try { return responder.handleRequest(); } catch (MyCustomException e1) { return Response.status(409).build(); } catch (UnauthorizedException e2) { return Response.status(401).build(); } catch (Exception e3) { return Response.status(500).build(); } }
...and use it via a lambda:
public Response myWebService1() { return respond(() -> { // Do stuff here, return a Response or throw / allow throws on error }); }
Since this is in a JAX-RS context, there is a much better way, that does not rely on catching a lot of different exceptions: use an ExceptionMapper
. This is a built-in mechanism of JAX-RS 1.0 that translates an exception type into a proper Response
object to send to the client.
In your case, you could have the following classes defined once in your application:
@Provider public class UnauthorizedExceptionMapper implements ExceptionMapper<UnauthorizedException> { public Response toResponse(UnauthorizedException e) { return Response.status(401).build(); } }
@Provider public class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException> { public Response toResponse(MyCustomException e) { return Response.status(409).build(); } }
@Provider public class CatchAllExceptionMapper implements ExceptionMapper<Exception> { public Response toResponse(Exception e) { return Response.status(500).build(); } }
The @Provider
annotation tells the JAX-RS runtime to discover this class when scanning. This makes sure that, wherever in your code, if a MyCustomException
is thrown (and not explicitly catched), a 409 response will be returned. The code in your application would simply become:
public Response myWebService1() { // do something, and don't catch anything; just care about the happy path }
The exception hierarchy is correctly taken into account. If the application code throws a MyCustomExceptionMapper
, JAX-RS will look for an exception mapper registered with that type, and will go up the super class if it can't find one: this way, there can be a catch-all exception mapper handling every other case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With