How return error message in spring mvc @Controller
Asked Answered
K

5

87

I am using methods like this

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<UserWithPhoto> getUser(@RequestHeader(value="Access-key") String accessKey,
                                     @RequestHeader(value="Secret-key") String secretKey){
    try{
        return new ResponseEntity<UserWithPhoto>((UserWithPhoto)this.userService.chkCredentials(accessKey, secretKey, timestamp),
                new HttpHeaders(),
                HttpStatus.CREATED);
    }
    catch(ChekingCredentialsFailedException e){
        e.printStackTrace();
        return new ResponseEntity<UserWithPhoto>(null,new HttpHeaders(),HttpStatus.FORBIDDEN);
    }
}

And I want to return some text message when exception occurs but now I just return status and null object. Is it possible to do?

Karaganda answered 7/9, 2015 at 15:23 Comment(3)
Change your return type to a ResponseEntity<Object> or to a ResponseEntity<?>. Instead of passing a null argument for your error case, pass in a String. Spring is smart enough to see the String and write it as text to the response body. Alternatively, provide a @ExceptionHandler that will handle the exception itself and have your handler throw the exception.Rotator
@SotiriosDelimanolis, wondering why don't you create answer?Orthman
@lkrnac I've answered similar questions in the past. I don't find them necessarily interesting anymore. But I couldn't find a duplicate, so I still wanted to give something.Rotator
V
156

As Sotirios Delimanolis already pointed out in the comments, there are two options:

Return ResponseEntity with error message

Change your method like this:

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity getUser(@RequestHeader(value="Access-key") String accessKey,
                              @RequestHeader(value="Secret-key") String secretKey) {
    try {
        // see note 1
        return ResponseEntity
            .status(HttpStatus.CREATED)                 
            .body(this.userService.chkCredentials(accessKey, secretKey, timestamp));
    }
    catch(ChekingCredentialsFailedException e) {
        e.printStackTrace(); // see note 2
        return ResponseEntity
            .status(HttpStatus.FORBIDDEN)
            .body("Error Message");
    }
}

Note 1: You don't have to use the ResponseEntity builder but I find it helps with keeping the code readable. It also helps remembering, which data a response for a specific HTTP status code should include. For example, a response with the status code 201 should contain a link to the newly created resource in the Location header (see Status Code Definitions). This is why Spring offers the convenient build method ResponseEntity.created(URI).

Note 2: Don't use printStackTrace(), use a logger instead.

Provide an @ExceptionHandler

Remove the try-catch block from your method and let it throw the exception. Then create another method in a class annotated with @ControllerAdvice like this:

@ControllerAdvice
public class ExceptionHandlerAdvice {

    @ExceptionHandler(ChekingCredentialsFailedException.class)
    public ResponseEntity handleException(ChekingCredentialsFailedException e) {
        // log exception
        return ResponseEntity
                .status(HttpStatus.FORBIDDEN)
                .body("Error Message");
    }        
}

Note that methods which are annotated with @ExceptionHandler are allowed to have very flexible signatures. See the Javadoc for details.

Vitellin answered 7/9, 2015 at 20:3 Comment(5)
I have been doing something similar to the second example here. I can't test it properly though. Do you know how to test the controller response using this method. Seems to work when you don't return your own ResponseEntity, but just use \@ResponseStatus and \@ResponseBody alongside \@ExceptionHandler.Collector
Should the class with the @ControllerAdvice try to handle all possible exceptions? For example if I throw a "weak password" exception, should I try catch it in the service method, or should I handle it in the exception handler class? How do we separate which exceptions are being handled by who? I know it's pretty subjective, but is there a standard practice?Viscount
To avoid a Raw use of parameterized class 'ResponseEntity warning, use ResponseEntity<?> as your method return type.Musaceous
what happens if you have Strong type object? eg ResponseEntity<Product> , then you cant throw errorRegulate
It would be useful to have public class ExceptionHandlerAdvice extends ResponseEntityExceptionHandler. (See this.)Lorusso
H
18

Here is an alternative. Create a generic exception that takes a status code and a message. Then create an exception handler. Use the exception handler to retrieve the information out of the exception and return to the caller of the service.

http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/

public class ResourceException extends RuntimeException {

    private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public ResourceException(HttpStatus httpStatus, String message) {
        super(message);
        this.httpStatus = httpStatus;
    }
}

Then use an exception handler to retrieve the information and return it to the service caller.

@ControllerAdvice
public class ExceptionHandlerAdvice { 

    @ExceptionHandler(ResourceException.class)
    public ResponseEntity handleException(ResourceException e) {
        // log exception 
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }         
} 

Then create an exception when you need to.

throw new ResourceException(HttpStatus.NOT_FOUND, "We were unable to find the specified resource.");
Hebraize answered 21/6, 2016 at 20:5 Comment(1)
what happens if you have Strong type object? eg ResponseEntity<Product> , then you cant throw errorRegulate
M
1

I´m not using the RepsoneEntitiy as return element because it destroys json format of the body. I found at this time of my posting this solution:

        throw new ResponseStatusException(
      HttpStatus.BAD_REQUEST, "ErrorMessage", optionalCauseExeption);

found here: https://www.baeldung.com/spring-response-status-exception

Moss answered 10/10, 2023 at 11:45 Comment(1)
This works great, you can additionally just define a handler to catch ResponseStatusExceptions and return a Map of errors. Thanks @Van.Inconvenient
K
-1

Evaluating the error response from another service invocated...

This was my solution for evaluating the error:

try {
        return authenticationFeign.signIn(userDto, dataRequest);
    }catch(FeignException ex){

        //ex.status();

        if(ex.status() == HttpStatus.UNAUTHORIZED.value()){
            System.out.println("is a error 401");
            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
        }
        return new ResponseEntity<>(HttpStatus.OK);

    }
Kenakenaf answered 3/2, 2020 at 15:38 Comment(0)
S
-6
return new ResponseEntity<>(GenericResponseBean.newGenericError("Error during the calling the service", -1L), HttpStatus.EXPECTATION_FAILED);
Stamina answered 23/10, 2018 at 9:48 Comment(1)
Where does GenericResponseBean come from?Guillemot

© 2022 - 2024 — McMap. All rights reserved.