2

In my Project, created exception handling using something like below approach. I mean we do throw new GeekAlreadyExistsException() in some service layer, and finally some error response(depending on error code) will be returned.

public interface ErrorCode {

    String code();

    HttpStatus httpStatus();

}

enum GeeksApiErrorCodes implements ErrorCode {
    GEEK_ALREADY_EXISTS("geeks-1", HttpStatus.BAD_REQUEST);

    private final String code;
    private final HttpStatus httpStatus;

    GeeksApiErrorCodes(String code, HttpStatus httpStatus) {
        this.code = code;
        this.httpStatus = httpStatus;
    }

    @Override
    public String code() {
        return code;
    }

    @Override
    public HttpStatus httpStatus() {
        return httpStatus;
    }
}
4
  • 2
    Rather then creating exception to error code mapping, why don't you put error code during creation/throwing of exception? Commented Oct 13, 2019 at 8:54
  • Mapping each error code with new exception class is not a good solution. If in future you need more error codes, you have have to create even more classes. Commented Oct 13, 2019 at 9:18
  • I have read that article, In my opinion it would be unnecessary to create these much exception classes, while we can do that will less number of classes, with itself contains error code and message. Do you need to do something special with exception class? In most of cases it is required either to log or to display some message to end user. And both scenarios can be handled with single exception class. Commented Oct 13, 2019 at 9:29
  • I have added my solution and I believe that will be enough for your requirement. Commented Oct 13, 2019 at 9:37

2 Answers 2

2

I would recommend making the exception know its own error code, e.g. something like this:

public abstract class ApplicationException extends RuntimeException {

    protected ApplicationException() {
        super();
    }
    protected ApplicationException(String message) {
        super(message);
    }
    protected ApplicationException(Throwable cause) {
        super(cause);
    }
    protected ApplicationException(String message, Throwable cause) {
        super(message, cause);
    }

    public abstract String getErrorCode();

    public abstract HttpStatus getHttpStatus();

}
public class GeekAlreadyExistsException extends ApplicationException {
    private static final long serialVersionUID = 1L;

    public GeekAlreadyExistsException() {
        super();
    }

    public GeekAlreadyExistsException(String message) {
        super(message);
    }

    public GeekAlreadyExistsException(String message, Throwable cause) {
        super(message, cause);
    }

    @Override
    public String getErrorCode() {
        return "geeks-1";
    }

    @Override
    public HttpStatus getHttpStatus() {
        return HttpStatus.BAD_REQUEST;
    }

}

If you don't want the one-errorcode-per-exception constraint, you can instead pass the error code on the constructor call.

That still allows some specialized subclass exceptions to hardcode the error code, so the caller cannot specify it.

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

    private final String errorCode;

    private final HttpStatus httpStatus;

    public ApplicationException(String errorCode, HttpStatus httpStatus) {
        super();
        this.errorCode = errorCode;
        this.httpStatus = httpStatus;
    }
    public ApplicationException(String errorCode, HttpStatus httpStatus, String message) {
        super(message);
        this.errorCode = errorCode;
        this.httpStatus = httpStatus;
    }
    public ApplicationException(String errorCode, HttpStatus httpStatus, Throwable cause) {
        super(cause);
        this.errorCode = errorCode;
        this.httpStatus = httpStatus;
    }
    public ApplicationException(String errorCode, HttpStatus httpStatus, String message, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
        this.httpStatus = httpStatus;
    }

    public final String getErrorCode() {
        return this.errorCode;
    }

    public final HttpStatus getHttpStatus() {
        return this.httpStatus;
    }

}
public class GeekAlreadyExistsException extends ApplicationException {
    private static final long serialVersionUID = 1L;

    public GeekAlreadyExistsException() {
        super("geeks-1", HttpStatus.BAD_REQUEST);
    }

    public GeekAlreadyExistsException(String message) {
        super("geeks-1", HttpStatus.BAD_REQUEST, message);
    }

    public GeekAlreadyExistsException(String message, Throwable cause) {
        super("geeks-1", HttpStatus.BAD_REQUEST, message, cause);
    }

}
Sign up to request clarification or add additional context in comments.

5 Comments

Still your solution too makes mapping exception to some error code, so GeekAlreadyExistsException should have to be used only for the error code: geeks-1 ? is this any best practise one custom exception to error code?
Wouldn't it result in "class explosion" ? You would have to create class for each error code and http status combination in worst scenario.
@john The premise of your question is that each exception is mapped to an error code and http status, so by that very nature, an exception can have only one error code. This is a solution that ensures you don't need 3 classes per exception.
@michalk The entire concept of exception mapper on the question limits to one error code per exception, so I stayed with that concept. If you want more generic reusable exceptions, you can do it the SQLException way and add errorCode as a constructor parameter. I've added that alternative to the answer.
@Andreas Now your updated looks good, I think super("geeks-1", HttpStatus.BAD_REQUEST); is not required, as its still like mapping exception to one error code
2

Mapping each error code with new exception class is not a good solution. If in future you need more error codes, you have have to create even more classes. So better solution will be populating error code during creation/throwing exception only. As below:

package test.file;

public class MyException extends RuntimeException {

  /**
   *
   */
  private static final long serialVersionUID = 1L;

  //The error code
  private final String errorCode;

  //The error message corresponding to the error code. Resolved on the basis of the Locale
  private final HttpStatus httpStatus;

  public MyException(final String errorCode, final HttpStatus httpStatus) {
    this.errorCode = errorCode;
    this.httpStatus = httpStatus;
  }

  public MyException(final String errorCode, final HttpStatus httpStatus, final Throwable cause) {
    super(cause);
    this.errorCode = errorCode;
    this.httpStatus = httpStatus;
  }

  public MyException(final String message, final String errorCode, final HttpStatus httpStatus, final Throwable cause) {
    super(message, cause);
    this.errorCode = errorCode;
    this.httpStatus = httpStatus;
  }

  /**
   * Method will return error code.
   *
   * @return
   */
  public String getErrorCode() {
    return errorCode;
  }

  /**
   * @return the httpStatus
   */
  public HttpStatus getHttpStatus() {
    return httpStatus;
  }

}

Here you can directly retrieve errorCode and perform appropriate action. That will fulfill your requirement what you have mentioned in question. This will be simplest solution for your problem.

2 Comments

Thanks Gaurav! One thing: As you mentioned "populating error code during creation/throwing exception only", I think we should populate error code while throwing exception, not while creating excepton.. Is this correct?
Yes that's correct. By creating I mean when object is being created before throwing.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.