简体   繁体   English

带有 Mono.empty() 参数的反应式 Java Mono.zip

[英]Reactive Java Mono.zip with Mono.empty() parameters

Using Spring with Reactor Project to zip multiple api calls as aggregated result.使用 Spring 和 Reactor 项目将多个 api 调用压缩为聚合结果。 Can Mono.zip() with Mono.empty() parameters return null result? Mono.zip() 和 Mono.empty() 参数可以返回空结果吗?

Mono<Dog> dogMono = dogApiClient.getDog(); // can return Mono.empty()
Mono<Cat> catMono = catMono = catApiClient.getCat(); // can returnMono.empty()
Mono<Horse> horseMono = horseApiClient.getHorse(); // can return Mono.empty()

Mono.zip(dogMono, dogMobo, horseMono)
  .map(this::mapToAnimals);

Expected result:预期结果:

{
  dog: null, // if dog is null
  cat: null, // if cat is null
  horse: null, // if horse is null
}

Actual result:实际结果:

{
  dog: {
    name: null,
    surname: null
  }, 
  cat: {
    name: null,
    surname: null
  }, 
  horse: {
    name: null,
    surname: null
  }
}

or或者

"" // empty

Well, it's certainly not an elegant solution, but you can choose to wrap your values inside Optional:好吧,这当然不是一个优雅的解决方案,但您可以选择将您的值包装在 Optional 中:

Mono<Optional<Dog>> dogMono = Mono.just(Optional.empty());
if(condition1) {
    dogMono = dogApiClient.getDog().map(Optional::of);
}

Mono<Optional<Cat>> catMono = Mono.just(Optional.empty());
if(condition2) {
    catMono = catApiClient.getCat().map(Optional::of);
}

Mono<Optional<Horse>> horseMono = Mono.just(Optional.empty());
if(condition3) {
    horseMono = horseApiClient.getHorse().map(Optional::of);
}

Mono.zip(dogMono, catMono, horseMono)
    .map(this::mapToAnimals);

private Output mapToAnimals(Tuple3<Optional<Dog>, Optional<Cat>, Optional<Horse>> tuple3)
{
    Dog dog = tuple3.getT1().orElse(null);
    Cat cat = tuple3.getT2().orElse(null);
    Horse horse = tuple3.getT3().orElse(null);

    return new Output(dog, cat, horse);
}

In Reactive Streams, the null value is forbidden.在 Reactive Streams 中, null值是被禁止的。 Furthermore, zip expect that all combined publishers have the same number of elements.此外, zip期望所有合并的发布者具有相同数量的元素。 Or to put it differently: it short-circuits as soon as one of the publishers completes.或者换一种说法:一旦其中一个出版商完成,它就会短路。

So if you use Mono.empty() , that Mono completes immediately and triggers the zip to complete empty as well.因此,如果您使用Mono.empty() ,则Mono立即完成并触发zip以完成清空。

One possible solution would be to have a "null object" instance of each animal, like this:一种可能的解决方案是为每个动物创建一个“空对象”实例,如下所示:

public static final Dog NO_DOG = new Dog(...);
public static final Cat NO_CAT = new Cat(...);
public static final Horse NO_HORSE = new Horse(...);

Mono<Dog> dogMono = (condition1) ? Mono.just(dogApliClient.getDog()) : Mono.just(NO_DOG);
Mono<Cat> catMono = (condition2) ? Mono.just(catApliClient.getCat()) : Mono.just(NO_CAT);
Mono<Horse> horseMono = (condition3) ? Mono.just(horseApliClient.getHorse()) : Mono.just(NO_HORSE);

Mono.zip(dogMono, catMono, horseMono)
    .map(Animals::fromDogCatAndHorse);

Map<String, Object> fromDogCatAndHorse(Tuple3<Dog, Cat, Horse> tuple) {
    Map<String, Object> forJson = new HashMap<>(3);

    Dog dog = tuple.getT1();
    if (dog = NO_DOG) json.put("dog", null); else json.put("dog", dog);

    Cat cat = tuple.getT2();
    if (cat = NO_CAT) json.put("cat", null); else json.put("cat", cat);

    Horse horse = tuple.getT3();
    if (horse = NO_HORSE) json.put("horse", null); else json.put("horse", horse);

    return forJson;
}

If you can't define these null object instances, then the solution from @yossarian would work too.如果您无法定义这些空对象实例,那么@yossarian 的解决方案也可以。

Note that there's still a big issue with the api client calls, though : the Mono.just(apiClient.blockingCall()) pattern.请注意,api 客户端调用仍然存在一个大问题Mono.just(apiClient.blockingCall())模式。

Here you're essentially shoehorning a blocking call inside what is supposed to be a non-blocking controller...在这里,您实际上是在应该是非阻塞控制器的内部硬塞进一个阻塞调用......

Ideally these clients would return a Mono<Dog|Cat|Horse> to reflect a non-blocking nature.理想情况下,这些客户端将返回Mono<Dog|Cat|Horse>以反映非阻塞性质。 As an example, with a proper non-blocking API, dogMono can be initialized like this:例如,使用适当的非阻塞 API,可以像这样初始化dogMono

Mono<Dog> dogMono = (condition1) ? dogApiClient.getDogAsync() : Mono.just(NO_DOG);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Reactor:Mono.zip 在空 Mono 上失败 - Spring Reactor: Mono.zip fails on empty Mono Mono怎么样<void>和 Mono.empty() 不同</void> - How are Mono<Void> and Mono.empty() different Spring Webflux:当 Mono.ZADC2BD79A8D84175C2Z29B19 中的一个 Mono 为空时处理错误 - Spring Webflux: Handle error when one Mono is empty in a Mono.zip mono.zip功能无法按预期工作 - mono.zip functionality not working as expected Spring WebFlux Mono 的异常中断 Mono.zip - Exception from a Spring WebFlux Mono interrupts Mono.zip 如何立即从Mono.zip返回服务器已发送事件? - How to immediately return Server Sent Events from Mono.zip? 根据类型处理来自 Mono.zip() 的异常 - Handle exceptions from Mono.zip() depending on type 为什么在 flatmap 中模拟 Mono.empty() 的响应会以错误结束? - Why does mocking a response of Mono.empty() inside flatmap end in error? 我如何使用 `Mono.zip(Iterable <!--? extends Mono<?--> > 单声道,Function<!--? super Object[],? extends R--> 组合子)` - How do I use `Mono.zip(Iterable<? extends Mono<?>> monos, Function<? super Object[],? extends R> combinator)` 为什么需要然后 Mono.empty() 在生成的默认实现中打开 API Spring 代码? - Why need to then Mono.empty() in the default implementation of generated Open API Spring code?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM