Home > front end >  How do I optionally chain another independent CompletableFuture if the first condition doesn't
How do I optionally chain another independent CompletableFuture if the first condition doesn't

Time:10-15

I have a method like this:

private CompletionStage<Void> example(final Resource resource) {
    return firstMatcher.match(resource)
        .whenComplete((op, t) -> {
            if (t != null || !op.isPresent()) {
                LOGGER.debug("resource doesn't match");
            }
        })
        .thenAccept(optMatch -> optMatch.ifPresent(match -> {
            LOGGER.debug("resource matches");

            // DONE
        }));

    // OR ELSE (Not sure how to chain this piece)

    return secondMatcher.match(resource)
        .whenComplete((op, t) -> {
            if (t != null || !op.isPresent()) {
                LOGGER.debug("resource doesn't match");
            }
        })
        .thenAccept(optMatch -> optMatch.ifPresent(match -> {
            LOGGER.debug("resource matches");

            // DONE
        }));

I would like to return a method that first matches my resource with the firstMatcher. If a match is found, it ends there. But if a match is not found, then it relies on the secondMatcher. Is it possible to chain this into a single method?

CodePudding user response:

You need something like this:

private CompletionStage<Void> example(final Resource resource) {
        return firstMatcher
                .match( resource )
                .thenCompose( firstMatch -> {
                    if ( firstMatch.isPresent() ) {
                        LOGGER.debug( "resource matches first" );
                        return CompletableFuture.completedFuture( null );
                    }
                    LOGGER.debug("resource doesn't match first");
                    return secondMatcher
                            .match( resource )
                            .thenCompose( secondMatch -> {
                                if ( secondMatch.isPresent() ) {
                                    LOGGER.debug( "resource matches second" );
                                    return CompletableFuture.completedFuture( null );
                                }
                                LOGGER.debug("resource doesn't match second");                       
                                // I'm returning a failed CompletionStage
                                // but you can add a third matcher or return something else.
                                // It depends on your requirements
                                return CompletableFuture.failed(new MatchNotFoundException());
                            });
                } );
}

Note that I've removed the whenComplete because they make the example more verbose, but you can add them back if you need to.

A possible refactoring:

    private CompletionStage<Void> example(final Resource resource) {
        return matches( firstMatcher.match( resource ), () -> matches( secondMatcher.match( resource ), () -> CompletionStages.failedFuture( new MatchNotFoundException() ) ) );
    }

    private static CompletionStage<Void> matches(CompletionStage<Optional<Object>> matcher, Supplier<CompletionStage<Void>> alternative) {
        return matcher
                .thenCompose( opt -> {
                    if ( opt.isPresent() ) {
                        LOGGER.debug( "resource matches" );
                        return CompletableFuture.completedFuture( null );
                    }
                    return alternative.get();
                } );
    }
  • Related