4

I have application with many rest services, most of them follows this pattern:

class RestService{

   public Response execute1() {
      try{
         // doLogicThere...

         return response;
       } catch () {
         // handle exception and build Response object..

         return response;
       }
   }

   public Response execute2() {
       try{
          // doLogicThere...

          return response;
       } catch() {
          // handle exception and build Response object..

          return response;
       }
   }
}

catch clause is the same for all methods so I want to have pattern like this below but with try/catch called from somewhere else. I want to do kind of wrapping these methods.

class RestService{

    public Response execute1() {
        // doLogicThere...

        return response;
    }

    public Response execute2() {
       // doLogicThere...

       return response;
    }
}
MagGGG
  • 19,198
  • 2
  • 29
  • 30
  • you either catch at the point you want the exception to occur, or you catch somewhere higher up in the call stack. – Marc B Jul 20 '16 at 14:13
  • Possible duplicate of [Avoid Empty Catch Blocks When Expecting Exception](http://stackoverflow.com/questions/38468125/avoid-empty-catch-blocks-when-expecting-exception) – jan.supol Jul 20 '16 at 14:16
  • 2
    as you are using spring, i recommend you to look at this https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc are you looking for something like that? – user902383 Jul 20 '16 at 14:34

5 Answers5

2

You can create an interface with the method you need to execute. Then you can wrap that method in a try catch in a new method. This will avoid the use of many repeated try catch blocks.

You can do something like that:

public interface CallableClass {
    public Response call();
}



...

class RestService {
    private Response handleCall(CallableClass myClass) {
        try {
            return myClass.call();
        } catch (Exception e) {
            // Handle exception and return a particular response
            ...
        }
    }

    public Response execute1() {
        return handleCall(/* put anonymous class of type CallableClass here */); 
    }

    public Response execute2() {
        return handleCall(/* put anonymous class of type CallableClass here */); 
    }

}

If you are using java 8 you can replace the anonynous class with a more elegant lambda expression.


Here a simple example with lambdas

public Response executeLambda() {
    return handleCall(() -> {
        ... // Your code here
        return response;
    });
}
Davide Lorenzo MARINO
  • 26,420
  • 4
  • 39
  • 56
2

JAX-WS includes a mechanism for creating the proper response for each type of exception that your REST methods might produce.

For each exception type, create a class that implements ExceptionMapper<E> where E is the type of exception. You create your response in the toResponse method. You need to annotate your exception mapper with @Provider, in order to register it with the JAX-RS runtime.

@Provider
public class UserNotFoundMapper implements ExceptionMapper<UserNotFoundException> {
    @Override
    public Response toResponse(UserNotFoundException e) {
        return Response.status(404).entity(e.getMessage()).type("text/plain").build();
    }
}
Rob
  • 6,247
  • 2
  • 25
  • 33
  • This was my first shoot. Unfortunatelly I was dealing with registration of this provider since I am using my custom web application containter. In some instances you have to manually register provider as you sometimes do for JacksonJsonProvider. – MagGGG Aug 10 '16 at 13:27
0

You can use the "throws" keyword to indicate that a method throws certain exceptions. Then when you call that method you can simply wrap the call in a try/catch block.

See: https://docs.oracle.com/javase/tutorial/essential/exceptions/declaring.html

Infamous911
  • 1,441
  • 2
  • 26
  • 41
0

If you are building RESTFul Service using SPring MVC, you do have a better option of leveraging using following annotation "@ExceptionHandler(CustomExceptionForRestServices.class)". Where you can write your customException or have a comma seperated List of exception classes you expect your method to throw.

The @ExceptionHandler value can be set to an array of Exception types. If an exception is thrown matches one of the types in the list, then the method annotated with the matching @ExceptionHandler will be invoked. If the annotation value is not set then the exception types listed as method arguments are used.

Much like standard controller methods annotated with a @RequestMapping annotation, the method arguments and return values of @ExceptionHandler methods are very flexible.

pendem
  • 16
  • 1
0

I have created a little example in plain AspectJ, i.e. without any Spring. I even created a dummy Response class just so as to show the basic mechanics behind aspect-driven exception handling:

Dummy response class:

package de.scrum_master.app;

public class Response {
    private int statusCode;
    private String message;

    public Response(int statusCode) {
        this.statusCode = statusCode;
        switch (statusCode) {
        case 200:
            message = "OK";
            break;
        case 202:
            message = "Accepted";
            break;
        case 401:
            message = "Unauthorized";
            break;
        default:
            message = "Unknown status";
        }
    }

    public int getStatusCode() {
        return statusCode;
    }

    @Override
    public String toString() {
        return "Response(statusCode=" + statusCode + ", message=" + message + ")";
    }
}

Driver application with two methods to be intercepted:

As you can see, both methods randomly throw exceptions which ought to be caught by an aspect later.

package de.scrum_master.app;

import java.util.Random;

public class RestService {
    private static final Random RANDOM = new Random();

    public Response someRequest() {
        Response response = new Response(RANDOM.nextBoolean() ? 200 : 401);
        if (response.getStatusCode() != 200)
            throw new RuntimeException("request failed: " + response);
        return response;
    }

    public Response anotherRequest(String argument) {
        Response response = new Response(RANDOM.nextBoolean() ? 200 : 401);
        if (response.getStatusCode() != 200)
            throw new RuntimeException("request failed: " + response);
        return response;
    }

    public static void main(String[] args) {
        RestService restService = new RestService();
        for (int i = 0; i < 3; i++) {
            System.out.println(restService.someRequest());
            System.out.println(restService.anotherRequest("foo"));
        }
    }
}

Exception handling aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import de.scrum_master.app.Response;

@Aspect
public class ResponseErrorHandler {
    @Around("execution(de.scrum_master.app.Response *(..))")
    public Response handleError(ProceedingJoinPoint thisJoinPoint) {
        System.out.println("\n" + thisJoinPoint);
        try {
            return (Response) thisJoinPoint.proceed();
        }
        catch (Exception e) {
            System.out.println("  Handling exception: " + e.getMessage());
            return new Response(202);
        }
    }
}

Console log:

execution(Response de.scrum_master.app.RestService.someRequest())
Response(statusCode=200, message=OK)

execution(Response de.scrum_master.app.RestService.anotherRequest(String))
Response(statusCode=200, message=OK)

execution(Response de.scrum_master.app.RestService.someRequest())
Response(statusCode=200, message=OK)

execution(Response de.scrum_master.app.RestService.anotherRequest(String))
  Handling exception: request failed: Response(statusCode=401, message=Unauthorized)
Response(statusCode=202, message=Accepted)

execution(Response de.scrum_master.app.RestService.someRequest())
Response(statusCode=200, message=OK)

execution(Response de.scrum_master.app.RestService.anotherRequest(String))
  Handling exception: request failed: Response(statusCode=401, message=Unauthorized)
Response(statusCode=202, message=Accepted)

Feel free to ask follow-up questions if you do not understand the answer.

kriegaex
  • 63,017
  • 15
  • 111
  • 202