Spring Webflux: Обрабатывает ошибку, когда один моно пуст в Mono.zip

#java #spring-webflux #project-reactor

Вопрос:

Мой код выглядит следующим образом

 public Mono<Ship> getShip() { 
    //... 
}

public Mono<Car> getCar() { 
    //... 
}

public Mono<ShipAndCar> getCombinedMono() {
    Mono<Ship> shipMono = getShip();
    Mono<Car> carMono = getCar();

    return Mono.zip(shipMono, carMono
                    (ship, car) -> return new ShipAndCar(ship, car);

}
 

Как getShip и getCar то, и другое, и может возвращать ошибку или пустое моно. Я хотел бы вернуть что-то вроде Mono.error(new Exception("Custom message")) того, где сообщение зависит от того, какой моно пуст. Как мне это сделать?

Если я добавлю a switchIfEmpty после Mono.zip, Я бы не знал, какой компонент Mono пуст…

Ответ №1:

Если вы заархивируете их в своем коде, вы можете расширить каждый входной моно с помощью оператора switchIfEmpty следующим образом

         var carAndShip = Mono.zip(
                Optional.ofNullable(shipMono)
                        .orElseThrow(() -> new RuntimeException("ship is null"))
                        .switchIfEmpty(Mono.error(new RuntimeException("ship is empty"))),
                Optional.ofNullable(carMono)
                        .orElseThrow(() -> new RuntimeException("car is null"))
                        .switchIfEmpty(Mono.error(new RuntimeException("car is empty"))),
                ShipAndCar::new
        );


 

Комментарии:

1. Он все равно будет выдавать NullPointerException при создании ShipAndCar , а не исключение RuntimeException 🙁

2. если значение pass может быть равно нулю, то вы можете добавить проверку с необязательным значением. Это выглядит немного уродливо, хотя.

3. Вопрос в том , что shipMono или carMono являются Mono.empty (), а не в том, что они являются нулевыми

Ответ №2:

Вы можете использовать сопоставление вспомогательных методов Optional , чтобы отложить решение о том, что делать, когда значение отсутствует, до более позднего потребителя.

Например, если вы просто хотите по умолчанию указать отсутствующее Ship , но ошибку в отсутствующем Car :

 package com.example.demo;

import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import java.util.Optional;

public class JavaTest {

    @Test
    public void nullCarProducesSpecificException() {
        Mono<Ship> shipMono = Mono.empty();
        Mono<Car> carMono = Mono.empty();

        Mono<ShipAndCar> map = Mono.zip(
            shipMono.transform(JavaTest::toOptional),
            carMono.transform(JavaTest::toOptional))
            .map(tuple -> new ShipAndCar(
                tuple.getT1().orElse(new Ship("US Default")),
                tuple.getT2().orElseThrow(() -> new RuntimeException("Car was missing!!")))
            );

        StepVerifier.create(map)
            .verifyErrorMatches(error ->
                error instanceof RuntimeException amp;amp;
                    "Car was missing!!".equals(error.getMessage())
            );

    }

    private static <T> Mono<Optional<T>> toOptional(Mono<T> mono) {
        return mono.map(Optional::of)
            .defaultIfEmpty(Optional.empty());
    }
}