0

I want to use custom exception handlers for my application. But, it is not working properly.

Here is my code

AuthenticationFilter.java

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    if (!bAuthorize) {
        chain.doFilter(request, response);
        return;
    }

    HttpServletRequest req = (HttpServletRequest) request;

    String namespace = getPathParamFromRequest(req, NAMESPACE_PATH_PREFIX);
    String userId =  getPathParamFromRequest(req, USER_PATH_PREFIX);


    AuthContext auth = null;
    RequestPathContext rpc = pathsList.getMatchingContext(req.getRequestURI(), HttpMethod.valueOf(req.getMethod()));
    if (rpc != null)
        auth = rpc.getAuthContext();

    if (auth != null) {
        // Authentication process
    } else {
        throw new UnauthorizedException();
    }
}

ApplicationExceptionHandler.java

public class ApplicationExceptionHandler {
  @ExceptionHandler(UnauthorizedException.class)
  public ResponseEntity<ErrorEntity> applicationxception(final UnauthorizedException e) {
    ErrorEntity errorEntity = new ErrorEntity(e.getNumericErrorCode(), e.getErrorCode(), e.getErrorMessage());
    return new ResponseEntity<>(errorEntity, HttpStatus.valueOf(e.getHttpStatus()));
  }
}

AuthFilterRegistration.java

@Configuration
public class AuthFilterRegistration {

  @Autowired
  private ApplicationContext context;

  @Bean
  public FilterRegistrationBean<AuthenticationFilter> loggingFilter() {
    FilterRegistrationBean<AuthenticationFilter> registrationBean
            = new FilterRegistrationBean<>();

    registrationBean.setFilter(context.getBean(AuthenticationFilter.class));
    registrationBean.addUrlPatterns( "/public/*");

    return registrationBean;
  }

  @Bean
  public AuthenticationFilter getAuthFilter() {
    return new AuthenticationFilter();
  }

  @Bean
  public ApplicationExceptionHandler getErrorHandler() {
    return new ApplicationExceptionHandler();
  }

}

ErrorEntity.java

public class ErrorEntity extends BaseErrorEntity {

  String errorMessage;

  Map<String, String> messageVariables;

  public ErrorEntity() {
  }

  public ErrorEntity(int numericErrorCode, String errorCode, String errorMessage) {
    this(numericErrorCode, errorCode, errorMessage, null);
  }

  public ErrorEntity(int numericErrorCode, String errorCode, String errorMessage, Map<String, String> messageVariables) {
    this.numericErrorCode = numericErrorCode;
    this.errorCode = errorCode;
    this.errorMessage = errorMessage;
    this.messageVariables = messageVariables;
  }

}

Using those code, I want to have an exception error like this

{
  "numericErrorCode": 2001,
  "errorCode": "errors.net.myproject.platform.unauthorized",
  "errorMessage": "unauthorized"
}

which is the instance of ErrorEntity, but I got this output

{
  "timestamp": "2019-02-01T04:41:14.337+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "unauthorized",
}

From the example it is clear that I cannot override the default Java exception completely. Only the message part that is altered successfully. Do I miss something here?

Rafi Ramadhan
  • 119
  • 1
  • 11
  • if I'm not mistaken, if you create your ExceptionHandlers with methods like that, they only work for the Exceptions thrown in the class in which they are defined – Stultuske Feb 01 '19 at 07:04
  • @Stultuske So, do you mean that the exception should also be defined in `AuthenticationFilter` class? – Rafi Ramadhan Feb 01 '19 at 07:10
  • No, I mean that if you want to implement an @ExceptionHandler the way you do, you should have it in the class where the Exception is thrown. But I don't see any methods that actually throw those Exceptions – Stultuske Feb 01 '19 at 07:12
  • I think I throw an `UnauthorizedException` inside the else block in `AuthenticationFilter` class. Or am I doing it wrong? – Rafi Ramadhan Feb 01 '19 at 07:18
  • @RafiRamadhan yet your method signature doesn't suggest your method can throw that Exception? – Stultuske Feb 01 '19 at 07:19
  • @RafiRamadhan did you used `@ControllerAdvice` annotation on your class? and this `@ResponseBody` on your handler method????? – Muhammad Waqas Feb 01 '19 at 07:23
  • @MuhammadWaqas Yes, I use `@ControllerAdvice`in `ApplicationExceptionHandler`class. And where should I put the `@ResponseBody` annotation? – Rafi Ramadhan Feb 01 '19 at 07:26
  • @Stultuske Do you mean the signature should be like this? `public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws UnauthorizedException`? – Rafi Ramadhan Feb 01 '19 at 07:30
  • Yes. And, as I said, that way of Error Handling only works for the Controller you've written the error handling method in. Check this link: https://www.baeldung.com/exception-handling-for-rest-with-spring – Stultuske Feb 01 '19 at 07:45

1 Answers1

4

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class ApplicationExceptionHandler extends ResponseEntityExceptionHandler {

@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public ResponseEntity<ErrorEntity> applicationxception(final UnauthorizedException e) {
    ErrorEntity errorEntity = new ErrorEntity(e.getNumericErrorCode(), e.getErrorCode(), e.getErrorMessage());
    return new ResponseEntity<>(errorEntity, HttpStatus.valueOf(e.getHttpStatus()));
}

@ResponseBody
@ExceptionHandler(RetrievedProfileException.class)
public ResponseEntity<ErrorEntity> applicationexception(final RetrievedProfileException e) {
    ErrorEntity errorEntity = new ErrorEntity(e.getNumericErrorCode(), e.getErrorCode(), e.getErrorMessage());
    return new ResponseEntity<>(errorEntity, HttpStatus.valueOf(e.getHttpStatus()));
}

I just extend this class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler because its pre- requsite

Secondly i used @ControllerAdvice

and lastly i used @ResponseBody

Use Exception Handler this way plus you should override the exception in this way.

Muhammad Waqas
  • 367
  • 3
  • 13
  • 1
    You may want to add what you changed and why it differs – Stultuske Feb 01 '19 at 07:26
  • I just extend this class `org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler` because its pre- requsite Secondly i used [`@ControllerAdvice`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html) and lastly i used [@ResponseBody](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html) – Muhammad Waqas Feb 01 '19 at 07:30
  • 2
    [Handle spring security authentication exceptions with @ExceptionHandler](https://stackoverflow.com/questions/19767267/handle-spring-security-authentication-exceptions-with-exceptionhandler) Check this post. Maybe this will help you. @RafiRamadhan – Muhammad Waqas Feb 01 '19 at 07:42