I am receiving a request in a 0.RestController
and give it to the service for processing. If service doesnt throw exception
, i just return HttpStatus.200
, but if an exception occurs in the service, i need catch it in controller and return the status depending on the exception.
Inside service, i need to use Mono.fromCallable
for repo access. Well, if user not found, i try throw my CustomException
, but i cant cach it in controller. What am I doing wrong?
Controller:
@RestController @RequiredArgsConstructor @Slf4j public class CardStatusController { private final CardStatusService cardStatusService; @PostMapping(value = "api/{user_id}/confirm", produces = {MediaType.APPLICATION_JSON_VALUE}) public Mono<ResponseEntity<HttpStatus>> confirmStatus( @PathVariable("user_id") String userId, @RequestBody CardStatusRequest statusRequest) { statusRequest.setUserId(userId); cardStatusService.checkCardStatus(statusRequest); return Mono.just(new ResponseEntity<>(HttpStatus.OK)); } @ExceptionHandler({ CheckCardStatusException.class }) public void handleException() { log.error("error!"); }
My service:
public Mono<Void> checkCardStatus(CardStatusRequest statusRequest) throws CheckCardStatusException { if (statusRequest.getCardEmissionStatus().equals(CardEmissionStatus.ACCEPTED)) { String reference = statusRequest.getReference(); return Mono.fromCallable(() -> userRepository.findById(statusRequest.getUserId())) .subscribeOn(Schedulers.boundedElastic()) .switchIfEmpty(Mono.error(new CheckCardStatusException(HttpStatus.NOT_FOUND))) .flatMap(user -> Mono.fromCallable(() -> cardRepository.findFireCardByUserId(user.getId())) .flatMap(optionalCard -> { if (optionalCard.isPresent()) { if (optionalCard.get().getExtId().isEmpty()) { Card card = optionalCard.get(); card.setExtId(reference); try { cardRepository.save(card); } catch (Exception e) { return Mono.error(new CheckCardStatusException(HttpStatus.INTERNAL_SERVER_ERROR)); } } else { if (!optionalCard.get().getExtId().equals(reference)) { return Mono.error(new CheckCardStatusException(HttpStatus.CONFLICT)); } } } else { Card card = new Card(); //set card params try { cardRepository.save(card); } catch (Exception e) { return Mono.error(new CheckCardStatusException(HttpStatus.INTERNAL_SERVER_ERROR)); } } return Mono.error(new CheckCardStatusException(HttpStatus.OK)); })).then(); } else { return Mono.error(new CheckCardStatusException(HttpStatus.OK)); } } }
My CustomException:
@AllArgsConstructor @Getter public class CheckCardStatusException extends RuntimeException { private HttpStatus httpStatus; }
Advertisement
Answer
The Mono
returned by checkCardStatus
is never subscribed, so the error signal is ignored. You have to return the whole chain to the Webflux framework as follows:
public Mono<ResponseEntity<HttpStatus>> confirmStatus( @PathVariable("user_id") String userId, @RequestBody CardStatusRequest statusRequest) { statusRequest.setUserId(userId); return cardStatusService.checkCardStatus(statusRequest) .then(Mono.just(new ResponseEntity<>(HttpStatus.OK))); }
In case of an error, the corresponding ExceptionHandler
will be executed.