7

In my application I have different layers like the rest layer, service layer and DB layer, according to business scenarios I am trowing different business exceptions from the service layer.

But now, I have to set different HTTP codes like 400, 403, 409, 412.. to REST responses.

How can I set different HTTP status codes based on different scenarios?

Which is the most feasible way like: aspect, exception mapper, or ....?

Since I can set HTTP status only once in rest layer ( referred this ), I am not able to map to different HTTP codes because my exception is from service layer.

My exception class looks like this:

public class BusinessException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public BusinessException(ErrorEnumeration error) {

    }
    public BusinessException(Exception e, ErrorEnumeration error) {

    }
}

and the exception will be thrown from the service like this:

 throw new BusinessException(ErrorEnumeration.VALIDATION_FAILED);

Please help by suggesting a solution

Community
  • 1
  • 1
Sunil Rk
  • 999
  • 6
  • 12
  • 35

1 Answers1

9

You can use exceptions defined in jax-rs or you can use your own exceptions. Fist catch your business exceptions and convert them to jax-rs versions. For example, for 404 you can throw javax.ws.rs.NotFoundException.

You can also write your own exceptions by extending them from javax.ws.rs.ClientErrorException

Here is an example for 409-Conflict status exception

import javax.ws.rs.ClientErrorException;
import javax.ws.rs.core.Response;

public class ConflictException extends ClientErrorException{

    public ConflictException(Response.Status status) {
        super(Response.Status.CONFLICT); // 409
    }
}

Update

Most simple and feasible way is catching your business exceptions and re-throw them with jax-rs exceptions.

try{
  businessService.executeBusinessRule();
}catch (BusinessException e){
  // It is better if your BusinessException has some child class to handle
  if(e.getError() == ErrorEnumeration.VALIDATION_FAILED){
    throw new BadRequestException();
  }else{
    throw new ConflictException();
  }
}

If you are using spring you can always catch these exceptions using aop.

@Aspect
public class BusinessExceptionInterceptor{
@AfterThrowing(pointcut = "execution(* com.your.service.packge..* (..))", throwing = "e")
public void errorInterceptor(BusinessException e) {
   // re-throw again...
}

Update 2

Also it is better to define a new exception instead of reusing same exception with different state. You can define a new ValidationException which extends from BusinessException like this.

public class ValidationException extends BusinessException{

    public ValidationException() {
        super(ErrorEnumeration.VALIDATION_FAILED);
    }
}

By using this way you can still handle all the BusinessException but it is easier to identify or map them to Jax-rs exceptions.

Westy92
  • 19,087
  • 4
  • 72
  • 54
bhdrkn
  • 6,244
  • 5
  • 35
  • 42
  • Hi, Thanks for a quick reply :) I have updated the question. – Sunil Rk Jun 23 '15 at 09:16
  • is it good add one more method in my "BusinessException" class like below ? public BusinessException(ErrorEnumeration error, Response.Status httpStatus) { } So that i can send the status while throwing itsef. – Sunil Rk Jun 23 '15 at 10:20
  • No not good. Your business layer should not be aware of which layer using it. You must detailed your exceptions, then handle them properly and last rethrow them in a form with status code. – bhdrkn Jun 23 '15 at 10:27
  • oh ok, but if i want to re-throw as u said i have to write catch or new exception class (referring your answer).Problem is i have around 35 different enumerations according business scenarios, i can't catch 35 exceptions for re-mapping or creating new classes also not recommendable.In this case how can i move ahead ? – Sunil Rk Jun 23 '15 at 10:47
  • Yes that will be a problem :). Just catch them with `businessException` exception. Then write a utility which generates exceptions according to your enumeration. You may use aop to catch them. This way you do not need to write `try...catch` statements. But you need to integrate aop, if you did not already – bhdrkn Jun 23 '15 at 11:31
  • Thanks for the clarification, it helped a lot .. :) – Sunil Rk Jun 24 '15 at 05:23
  • ConflictException is not in Jersey 2 anymore. I am digging to see what I can replace it with (after attempts to migrate from Jersey 1.18 to 2.16) – Raf Mar 12 '20 at 16:58