首页 > 解决方案 > Project Reactor:实现有条件地映射输入Mono

问题描述

我正在尝试实现以下简单的命令式逻辑:

boolean saveImperative(final List list) {
    final String existingList = readByNameImperative(list.getName());
    if (Objects.isNull(existingList)) {
        templateSaveImperative(existingList);
        return true;
    } else {
        templateSaveImperative(existingList);
        return false;
    }
}

以声明方式使用 Project Reactor,这就是我能够实现的目标:

@Test
public void testDeclarative() {
    final Mono<List> list = createList("foo");
    final Boolean result = save(list).block();
    System.out.println(result);
}

private Mono<Boolean> save(final Mono<List> listMono) {
    final Mono<List> existingListMono = listMono.cache()
            .flatMap(list -> readByName(list.getName()));
    // if
    final Mono<List> savedListMono = existingListMono
            .flatMap(existingList -> templateSave(Mono.just(existingList)));
    final Mono<Boolean> trueResult = savedListMono.map(x -> true);

    // else
    return trueResult.switchIfEmpty(templateSave(existingListMono).map(x -> false));
}

private Mono<List> templateSave(final Mono<List> listMono) {
    return listMono.map(list -> {
        System.out.println("templateSave has been called");
        return list;
    });
}

private Mono<List> readByName(final String listName) {
    if (listName != "list001") {
        return Mono.empty();
    }

    return createList(listName);
}

private Mono<List> createList(final String name) {
    final List list = List.builder().name(name).build();
    return Mono.just(list);
}

@Value
@Builder
private static class List {
    private final String name;
}

如果我用 执行测试list001,它将打印:

templateSave has been called
true

正如预期的那样,但如果我用 调用它foo,那么我得到了

null

我会错过什么?我希望输出如下:

templateSave has been called
false

在这种情况下。

标签: project-reactorreactivedeclarative

解决方案


final Mono<List> existingListMono = listMono.cache()
    .flatMap(list -> readByName(list.getName()));

...在您的保存方法中,将获取您现有的列表并使用readByName().

您的readByName()方法如下:

private Mono<List> readByName(final String listName) {
    if (listName != "list001") {
        return Mono.empty();
    }

    return createList(listName);
}

(我不相信它与这个问题有关,但不要使用 == 或 != 来比较字符串。)

由于您的listNameis foo, not list001,它返回一个空Mono- 因此existingListMono成为一个空 Mono,并且暗示也是如此savedListMonoand trueResult

但是,当您调用您的switchIfEmpty()语句时,您传入templateSave(existingListMono)- 并且由于如上所述existingListMono是空的,因此该方法返回一个 empty 。Monosave()Mono

...并且当您阻塞空时,Mono您将得到 null - 因此结果。

因此,您可能希望在方法的 return 语句中使用listMono而不是,这将为您提供您所追求的结果:existingListMonosave()

trueResult.switchIfEmpty(templateSave(listMono).map(x -> false))

推荐阅读