5
respostas

pq não consigo jogar exception na response do postman?

tenho esse seguinte metodo:

private void searchLoja(List itensloja) {// itenslojar n estao sendo usados por enquanto pq to mockando os valores ali final var idsLojas = List.of(2, 69998787); valid(idsLojas).subscribe(); }

private Mono<Void> valid(List<Integer> lojas) {
    return Flux.fromIterable(lojas)
        .flatMap(id -> repository.existsByLojaId(id)
            .flatMap(exists -> {
                System.out.println(exists);
                if (!exists) {
                    throw ExceptionUtils.buildException(
                        HttpStatus.NOT_FOUND,
                        "message.lojaid.not_found",
                         id.toString());
                }
                return Mono.empty();
            }))
        .then();
}

ele joga a exceção no console mas não vem na response, parece q não ta seguindo no fluxo e não há nenhum tratamento, eu chamo o metodo apenas

o repository vem mono<boolean>, aqueles valores estao mockados um é true  eoutro false, logo era pra jogar a exceção e vir 404, tem outro código q utiliza a mesma exceção e funciona então acho que é problema no meu webflux q fiz ali, alguma sugestão?
5 respostas

Olá, Jade! Como vai?

Pelo que entendi, você está tentando lançar uma exceção quando o método existsByLojaId(id) retorna false, correto? O problema é que, quando você lança a exceção dentro do flatMap, ela não é propagada para o fluxo principal do Spring WebFlux. Isso acontece porque o flatMap lida com a exceção e não a propaga para o fluxo principal.

Uma maneira de resolver isso é usando o operador switchIfEmpty que é chamado quando o Mono está vazio. No seu caso, quando exists é false, você pode retornar um Mono.empty(), e então o switchIfEmpty será chamado e você pode lançar sua exceção lá.

Aqui está um exemplo de como você pode fazer isso:

private Mono<Void> valid(List<Integer> lojas) {
    return Flux.fromIterable(lojas)
        .flatMap(id -> repository.existsByLojaId(id)
            .flatMap(exists -> {
                System.out.println(exists);
                if (!exists) {
                    return Mono.empty();
                }
                return Mono.just(id);
            })
            .switchIfEmpty(Mono.error(ExceptionUtils.buildException(
                HttpStatus.NOT_FOUND,
                "message.lojaid.not_found",
                id.toString())))
        )
        .then();
}

Neste exemplo, se exists for false, um Mono.empty() é retornado, o que faz com que o switchIfEmpty seja chamado e a exceção seja lançada.

Espero ter ajudado e bons estudos!

oi prof, apliquei este código sugerido, mas ainda assim, no body vem o model com valores null/vazio e status 200, ele não ta parando o fluxo, só jogou a exception no console

Tenta assim então, utilizando o Mono.error:

private Mono<Void> valid(List<Integer> lojas) {
    return Flux.fromIterable(lojas)
        .flatMap(id -> repository.existsByLojaId(id)
            .flatMap(exists -> {
                if (!exists) {
                    return Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND, "message.lojaid.not_found", id.toString()));
                }
                return Mono.empty();
            }))
        .then();
}

mesmo resultado prof será que não é a forma que é chamado? com subscribe? pois tem outro ponto onde lança essa exception e dá 404, não seria minha exception, mas acho q algo ali no webflux eu chamo o metodo, e na sequencia tem o return .... fluxo de dados sendo manipulados...., coloquei o metodo antes deste return deste fluxo justamente, não existe a loja, não faz sentido fazer o fluxo, mas ele cai ali, o metodo não ta parando o codigo

Entendi a situação. Parece que o problema pode estar relacionado à forma como você está consumindo o Mono retornado pelo método valid. O Mono representa um fluxo de dados reativos, e ele não bloqueará automaticamente a execução do código. Se você deseja que a exceção lançada no método valid pare a execução e seja refletida na resposta HTTP, você precisa tratar isso adequadamente na chamada ao método.

Duas opções para resolver isso:

1 - Usar block: Embora o uso de block não seja a abordagem ideal em um ambiente reativo, ele pode ser útil em casos onde você deseja bloquear a execução até que o Mono seja concluído. No entanto, lembre-se de que o uso excessivo de block pode levar a problemas de desempenho em aplicativos reativos:

try {
    //chamada ao método
    valid(idsLojas).block();
} catch (Exception e) {
    // Trate a exceção aqui
}

2 - Tratar a exceção assincronamente: Em vez de usar subscribe, você pode usar onErrorResume para capturar a exceção e retornar uma resposta HTTP adequada. Isso permitirá que você mantenha o fluxo reativo e trate a exceção de maneira assíncrona.

private Mono<Void> searchLoja(List<Integer> idsLojas) {
    return valid(idsLojas)
        .onErrorResume(e -> {
            if (e instanceof ResponseStatusException) {
                return Mono.error(e); // Passar a exceção para a resposta HTTP
            } else {
                return Mono.error(new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Erro interno", e));
            }
        });
}