Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a good example of zalando-problem implementation in spring boot?

We are using zalando-problem for exception handling in our spring-boot application. but looks like our problem handlers are never called. Instead spring boot returns 500 Internal server error for all the exceptions. If you can provide some examples it will be helpful. I couldn't find a good example of zalando-problem implementation in spring boot

If the user is not logged in, the code is throwing SSOAuthenticationException exception.

@Immutable
public class SSOAuthenticationException extends AbstractThrowableProblem {

    private final String errorMessage;

    public SSOAuthenticationException( final String errorMessage ) {
        super( ErrorConstants.SSO_CACHE_AUTHENTICATION_FAILED, errorMessage, Status.UNAUTHORIZED );
        this.errorMessage = errorMessage;
    }

    public String getErrorMessage(){
        return errorMessage;
    }
    @Override
    public String toString() {
        return "SSOAuthenticationException{}";
    }
}

And the Exception handling code:

@ControllerAdvice
public class ExceptionTranslator implements ProblemHandling {
    @Override
    public ResponseEntity<Problem> process(@Nullable ResponseEntity<Problem> entity, NativeWebRequest request) {
        if (entity == null) {
            return entity;
        }
        Problem problem = entity.getBody();
        if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) {
            return entity;
        }
        ProblemBuilder builder = Problem.builder()
            .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType())
            .withStatus(problem.getStatus())
            .withTitle(problem.getTitle())
            .with("path", request.getNativeRequest(HttpServletRequest.class).getRequestURI());

        if (problem instanceof ConstraintViolationProblem) {
            builder
                .with("violations", ((ConstraintViolationProblem) problem).getViolations())
                .with("message", ErrorConstants.ERR_VALIDATION);
        } else {
            builder
                .withCause(((DefaultProblem) problem).getCause())
                .withDetail(problem.getDetail())
                .withInstance(problem.getInstance());
            problem.getParameters().forEach(builder::with);
            if (!problem.getParameters().containsKey("message") && problem.getStatus() != null) {
                builder.with("message", "error.http." + problem.getStatus().getStatusCode());
            }
        }
        return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode());
    }

    @ExceptionHandler(SSOAuthenticationException.class)
    @ResponseBody
    public ResponseEntity<Problem> handleUnAuthenticatedUser(SSOAuthenticationException ex, NativeWebRequest request) {
        Problem problem = Problem.builder()
            .withStatus(Status.UNAUTHORIZED)
            .with("message", ErrorConstants.SSO_CACHE_AUTHENTICATION_FAILED)
            .build();
        return create(ex, problem, request);
    }
}

When I run in debugger, I notice that the exception handler is never called. instead the code thinks there is no handler registered (In ServletInitialHandler.java, it goes to the else section which is for exception not handled) and changes the status code to INTERNAL_SERVER_ERROR. So for all the exceptions, the application throws error 500. What is wrong in the exception handling code? Do we have to include a AdviceTrait? I tried that as well. but looks like that is also not working. If you could explain the right way of handling this exception and an example, it helps. Thanks

like image 786
Sharvari Nagesh Avatar asked Apr 11 '19 00:04

Sharvari Nagesh


Video Answer


1 Answers

Using Problem Spring Web 0.25.2, I first created a new AdviceTrait similar to the existing ones:

public interface CustomAdviceTrait extends AdviceTrait {

  @ExceptionHandler
  default ResponseEntity<Problem> handleCustomException(final CustomException exception, final NativeWebRequest request) {
    return create(Status.INTERNAL_SERVER_ERROR, exception, request);
  }
}

This is also where a conversion into a Problem could take place, if needed.

Then, likewise to enabling dedicated built-in advice traits I enable them by implementing the respective interface on my ExceptionHandler:

@ControllerAdvice
public class FootlooseServiceExceptionHandler implements ProblemHandling, CustomAdviceTrait { }
like image 147
mthomas Avatar answered Oct 12 '22 02:10

mthomas