Skip to content
Advertisement

How throws CustomException from reactive service to controller?

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.

8 People found this is helpful
Advertisement