0

I have an already implemented controller method which returns a value or throws an exception.

@Override
    @PostMapping(Endpoint.SUB_RESOURCE)
    @ResponseStatus(HttpStatus.CREATED)
    public EmployeeBankAccountOutputDto createBankAccount(@ApiParam("Account data") @RequestBody final EmployeeBankAccountInputDto accountCreationDto) {

        try {
            return service.createBankAccount(accountCreationDto);
        } catch (InvalidAccountDataException ex) {
            throw new InvalidAccountDataResponseException(ex, ex.getErrors());} 
        } catch (CountryNotFoundException ex) {
            throw new CountryNotFoundResponseException(ex.getCountryCode(), ex);
        }
    }

In this code I want to just log exception message in warning level and not throwing exception because I don't want to see something like :

14:37:02,610 ERROR [] c.m.w.ApiExceptionHandler:135 -  Account API error occurred: 400

So if I just put

log.warn(ex.getMessage()); to the first catch statement, it is giving

missing return statement

error for that catch block as normal. So How can handle not throwing exception to calling api and just send the exception message properly, because return type of the method is a dto?

2
  • Possible duplicate of How return error message in spring mvc @Controller Commented Jan 18, 2019 at 13:54
  • Try implementing an exception handler by extending ResponseEntityExceptionHandler . Commented Jan 18, 2019 at 13:54

2 Answers 2

4

If the account could not be created you don't want to return nothing.
At least you want to return a 400 error response to signal to the client the issue.

You could use ResponseEntity as return type of your method to signal the response code. It also means that you will have to change the way of return the object in the successful case too.
You could change the method in this way if you don't want to transmit the specific error message but only the error code :

public ResponseEntity<EmployeeBankAccountOutputDto> createBankAccount(@ApiParam("Account data") @RequestBody final EmployeeBankAccountInputDto accountCreationDto) {

    try {
        return  ResponseEntity.ok(service.createBankAccount(accountCreationDto));
    } catch (InvalidAccountDataException ex) {
      log.warn(ex.getMessage());
      return ResponseEntity.badRequest();
    } 
}

If you also want to transmit the specific error message you could use the body of the response :

public ResponseEntity<EmployeeBankAccountOutputDto> createBankAccount(@ApiParam("Account data") @RequestBody final EmployeeBankAccountInputDto accountCreationDto) {

    try {
        return  ResponseEntity.ok(service.createBankAccount(accountCreationDto));
    } catch (InvalidAccountDataException ex) {
      log.warn(ex.getMessage());
      return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
    } 
}

Note that if you need to perform this processings in multiple controllers it probably means that an exception handler would be a neater approach.
For example to handle InvalidAccountDataException in an uniform way :

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

    Logger LOGGER = LoggerFactory.getLogger(MyExceptionHandler.class);

    @ExceptionHandler(value = { InvalidAccountDataException.class })
    protected ResponseEntity<Object> handleGenericExceptions(InvalidAccountDataException ex, WebRequest request) {
        log.warn(ex.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());      
    }

}

You can add more methods to handle more types of exception if required of course.

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

4 Comments

I was thinking about writing almost the same. +1
@J-Alex Thanks for your fair :)
if I use responseentity what about calling api ? it does not be affected right ? or do I need to change in calling api also ?
No it changes nothing for clients. It is a just an abstraction for the implementation side.
3

If you don't throw the exception from the 1st catch block and an exception is thrown and caught in that case what should the method return?

That is why you are getting a compiler error as there will be no return value as either a return statement is missing or an exception is not thrown which would've caused the execution flow to stop abruptly, so instead you can do the following:

public EmployeeBankAccountOutputDto createBankAccount(@ApiParam("Account data") @RequestBody final EmployeeBankAccountInputDto accountCreationDto) {
       EmployeeBankAccountInputDto employeeBankAccountInputDto = null;
       try {
            employeeBankAccountInputDto = service.createBankAccount(accountCreationDto);
       } catch (InvalidAccountDataException ex) {
          log.warn(ex.getMessage()); 
       } catch (CountryNotFoundException ex) {
           throw new CountryNotFoundResponseException(ex.getCountryCode(), ex);
       }
       return employeeBankAccountInputDto;
}

You should ideally wrap the returned object in a ResponseEntity and add a message & response code (as davidxxx explains in his comment).

public ResponseEntity<EmployeeBankAccountOutputDto> createBankAccount(@ApiParam("Account data") @RequestBody final EmployeeBankAccountInputDto accountCreationDto) {
       EmployeeBankAccountInputDto employeeBankAccountInputDto = null;
       try {
            employeeBankAccountInputDto = service.createBankAccount(accountCreationDto);
       } catch (InvalidAccountDataException ex) {
            log.warn(ex.getMessage()); 
            return new ResponseEntity(employeeBankAccountInputDto, HttpStatus.BAD_REQUEST);
       } catch (CountryNotFoundException ex) {
            throw new CountryNotFoundResponseException(ex.getCountryCode(), ex);
       }
       return new ResponseEntity(employeeBankAccountInputDto, HttpStatus.OK);
 }

1 Comment

In your first approach you will return a 2XX response code. Clients should not consider successful response as an issue. I think that you should keep only the second way.

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.