All Downloads are FREE. Search and download functionalities are using the official Maven repository.

reactor.core.publisher.Mono Maven / Gradle / Ivy

Go to download

Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC

There is a newer version: 3.40.2
Show newest version
/*
 * Copyright (c) 2016-2023 VMware Inc. or its affiliates, All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package reactor.core.publisher;

import java.time.Duration;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.LongConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.logging.Level;

import io.micrometer.core.instrument.MeterRegistry;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import reactor.core.CorePublisher;
import reactor.core.CoreSubscriber;
import reactor.core.Disposable;
import reactor.core.Exceptions;
import reactor.core.Fuseable;
import reactor.core.Scannable;
import reactor.core.publisher.FluxOnAssembly.AssemblySnapshot;
import reactor.core.publisher.FluxOnAssembly.CheckpointHeavySnapshot;
import reactor.core.publisher.FluxOnAssembly.CheckpointLightSnapshot;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Scheduler.Worker;
import reactor.core.scheduler.Schedulers;
import reactor.util.Logger;
import reactor.util.Metrics;
import reactor.util.annotation.Nullable;
import reactor.util.concurrent.Queues;
import reactor.util.context.Context;
import reactor.util.context.ContextView;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuple3;
import reactor.util.function.Tuple4;
import reactor.util.function.Tuple5;
import reactor.util.function.Tuple6;
import reactor.util.function.Tuple7;
import reactor.util.function.Tuple8;
import reactor.util.function.Tuples;
import reactor.core.observability.SignalListener;
import reactor.core.observability.SignalListenerFactory;
import reactor.util.retry.Retry;

/**
 * A Reactive Streams {@link Publisher} with basic rx operators that emits at most one item via the
 * {@code onNext} signal then terminates with an {@code onComplete} signal (successful Mono,
 * with or without value), or only emits a single {@code onError} signal (failed Mono).
 *
 * 

Most Mono implementations are expected to immediately call {@link Subscriber#onComplete()} * after having called {@link Subscriber#onNext(T)}. {@link Mono#never() Mono.never()} is an outlier: it doesn't * emit any signal, which is not technically forbidden although not terribly useful outside * of tests. On the other hand, a combination of {@code onNext} and {@code onError} is explicitly forbidden. * *

* The recommended way to learn about the {@link Mono} API and discover new operators is * through the reference documentation, rather than through this javadoc (as opposed to * learning more about individual operators). See the * "which operator do I need?" appendix. * *

* *

* *

The rx operators will offer aliases for input {@link Mono} type to preserve the "at most one" * property of the resulting {@link Mono}. For instance {@link Mono#flatMap flatMap} returns a * {@link Mono}, while there is a {@link Mono#flatMapMany flatMapMany} alias with possibly more than * 1 emission. * *

{@code Mono} should be used for {@link Publisher} that just completes without any value. * *

It is intended to be used in implementations and return types, input parameters should keep * using raw {@link Publisher} as much as possible. * *

Note that using state in the {@code java.util.function} / lambdas used within Mono operators * should be avoided, as these may be shared between several {@link Subscriber Subscribers}. * * @param the type of the single value of this class * @author Sebastien Deleuze * @author Stephane Maldini * @author David Karnok * @author Simon Baslé * @see Flux */ public abstract class Mono implements CorePublisher { // ============================================================================================================== // Static Generators // ============================================================================================================== /** * Creates a deferred emitter that can be used with callback-based * APIs to signal at most one value, a complete or an error signal. *

* *

* Bridging legacy API involves mostly boilerplate code due to the lack * of standard types and methods. There are two kinds of API surfaces: * 1) addListener/removeListener and 2) callback-handler. *

* 1) addListener/removeListener pairs
* To work with such API one has to instantiate the listener, * call the sink from the listener then register it with the source: *


	 * Mono.<String>create(sink -> {
	 *     HttpListener listener = event -> {
	 *         if (event.getResponseCode() >= 400) {
	 *             sink.error(new RuntimeException("Failed"));
	 *         } else {
	 *             String body = event.getBody();
	 *             if (body.isEmpty()) {
	 *                 sink.success();
	 *             } else {
	 *                 sink.success(body.toLowerCase());
	 *             }
	 *         }
	 *     };
	 *
	 *     client.addListener(listener);
	 *
	 *     sink.onDispose(() -> client.removeListener(listener));
	 * });
	 * 
* Note that this works only with single-value emitting listeners. Otherwise, * all subsequent signals are dropped. You may have to add {@code client.removeListener(this);} * to the listener's body. *

* 2) callback handler
* This requires a similar instantiation pattern such as above, but usually the * successful completion and error are separated into different methods. * In addition, the legacy API may or may not support some cancellation mechanism. *


	 * Mono.<String>create(sink -> {
	 *     Callback<String> callback = new Callback<String>() {
	 *         @Override
	 *         public void onResult(String data) {
	 *             sink.success(data.toLowerCase());
	 *         }
	 *
	 *         @Override
	 *         public void onError(Exception e) {
	 *             sink.error(e);
	 *         }
	 *     }
	 *
	 *     // without cancellation support:
	 *
	 *     client.call("query", callback);
	 *
	 *     // with cancellation support:
	 *
	 *     AutoCloseable cancel = client.call("query", callback);
	 *     sink.onDispose(() -> {
	 *         try {
	 *             cancel.close();
	 *         } catch (Exception ex) {
	 *             Exceptions.onErrorDropped(ex);
	 *         }
	 *     });
	 * });
	 * 
* @param callback Consume the {@link MonoSink} provided per-subscriber by Reactor to generate signals. * @param The type of the value emitted * @return a {@link Mono} */ public static Mono create(Consumer> callback) { return onAssembly(new MonoCreate<>(callback)); } /** * Create a {@link Mono} provider that will {@link Supplier#get supply} a target {@link Mono} to subscribe to for * each {@link Subscriber} downstream. * *

* *

* @param supplier a {@link Mono} factory * @param the element type of the returned Mono instance * @return a deferred {@link Mono} * @see #deferContextual(Function) */ public static Mono defer(Supplier> supplier) { return onAssembly(new MonoDefer<>(supplier)); } /** * Create a {@link Mono} provider that will {@link Function#apply supply} a target {@link Mono} * to subscribe to for each {@link Subscriber} downstream. * This operator behaves the same way as {@link #defer(Supplier)}, * but accepts a {@link Function} that will receive the current {@link ContextView} as an argument. * *

* *

* @param contextualMonoFactory a {@link Mono} factory * @param the element type of the returned Mono instance * @return a deferred {@link Mono} deriving actual {@link Mono} from context values for each subscription */ public static Mono deferContextual(Function> contextualMonoFactory) { return onAssembly(new MonoDeferContextual<>(contextualMonoFactory)); } /** * Create a Mono which delays an onNext signal by a given {@link Duration duration} * on a default Scheduler and completes. * If the demand cannot be produced in time, an onError will be signalled instead. * The delay is introduced through the {@link Schedulers#parallel() parallel} default Scheduler. * *

* *

* @param duration the duration of the delay * * @return a new {@link Mono} */ public static Mono delay(Duration duration) { return delay(duration, Schedulers.parallel()); } /** * Create a Mono which delays an onNext signal by a given {@link Duration duration} * on a provided {@link Scheduler} and completes. * If the demand cannot be produced in time, an onError will be signalled instead. * *

* *

* @param duration the {@link Duration} of the delay * @param timer a time-capable {@link Scheduler} instance to run on * * @return a new {@link Mono} */ public static Mono delay(Duration duration, Scheduler timer) { return onAssembly(new MonoDelay(duration.toNanos(), TimeUnit.NANOSECONDS, timer)); } /** * Create a {@link Mono} that completes without emitting any item. * *

* *

* @param the reified {@link Subscriber} type * * @return a completed {@link Mono} */ public static Mono empty() { return MonoEmpty.instance(); } /** * Create a {@link Mono} that terminates with the specified error immediately after * being subscribed to. *

* *

* @param error the onError signal * @param the reified {@link Subscriber} type * * @return a failing {@link Mono} */ public static Mono error(Throwable error) { return onAssembly(new MonoError<>(error)); } /** * Create a {@link Mono} that terminates with an error immediately after being * subscribed to. The {@link Throwable} is generated by a {@link Supplier}, invoked * each time there is a subscription and allowing for lazy instantiation. *

* *

* @param errorSupplier the error signal {@link Supplier} to invoke for each {@link Subscriber} * @param the reified {@link Subscriber} type * * @return a failing {@link Mono} */ public static Mono error(Supplier errorSupplier) { return onAssembly(new MonoErrorSupplied<>(errorSupplier)); } /** * Pick the first {@link Mono} to emit any signal (value, empty completion or error) * and replay that signal, effectively behaving like the fastest of these competing * sources. *

* *

* @param monos The deferred monos to use. * @param The type of the function result. * * @return a new {@link Mono} behaving like the fastest of its sources. * @deprecated use {@link #firstWithSignal(Mono[])}. To be removed in reactor 3.5. */ @SafeVarargs @Deprecated public static Mono first(Mono... monos) { return firstWithSignal(monos); } /** * Pick the first {@link Mono} to emit any signal (value, empty completion or error) * and replay that signal, effectively behaving like the fastest of these competing * sources. *

* *

* @param monos The deferred monos to use. * @param The type of the function result. * * @return a new {@link Mono} behaving like the fastest of its sources. * @deprecated use {@link #firstWithSignal(Iterable)}. To be removed in reactor 3.5. */ @Deprecated public static Mono first(Iterable> monos) { return firstWithSignal(monos); } /** * Pick the first {@link Mono} to emit any signal (value, empty completion or error) * and replay that signal, effectively behaving like the fastest of these competing * sources. *

* *

* @param monos The deferred monos to use. * @param The type of the function result. * * @return a new {@link Mono} behaving like the fastest of its sources. */ @SafeVarargs public static Mono firstWithSignal(Mono... monos) { return onAssembly(new MonoFirstWithSignal<>(monos)); } /** * Pick the first {@link Mono} to emit any signal (value, empty completion or error) * and replay that signal, effectively behaving like the fastest of these competing * sources. *

* *

* @param monos The deferred monos to use. * @param The type of the function result. * * @return a new {@link Mono} behaving like the fastest of its sources. */ public static Mono firstWithSignal(Iterable> monos) { return onAssembly(new MonoFirstWithSignal<>(monos)); } /** * Pick the first {@link Mono} source to emit any value and replay that signal, * effectively behaving like the source that first emits an * {@link Subscriber#onNext(Object) onNext}. * *

* Valued sources always "win" over an empty source (one that only emits onComplete) * or a failing source (one that only emits onError). *

* When no source can provide a value, this operator fails with a {@link NoSuchElementException} * (provided there are at least two sources). This exception has a {@link Exceptions#multiple(Throwable...) composite} * as its {@link Throwable#getCause() cause} that can be used to inspect what went wrong with each source * (so the composite has as many elements as there are sources). *

* Exceptions from failing sources are directly reflected in the composite at the index of the failing source. * For empty sources, a {@link NoSuchElementException} is added at their respective index. * One can use {@link Exceptions#unwrapMultiple(Throwable) Exceptions.unwrapMultiple(topLevel.getCause())} * to easily inspect these errors as a {@link List}. *

* Note that like in {@link #firstWithSignal(Iterable)}, an infinite source can be problematic * if no other source emits onNext. *

* * * @param monos An {@link Iterable} of the competing source monos * @param The type of the element in the sources and the resulting mono * * @return a new {@link Mono} behaving like the fastest of its sources */ public static Mono firstWithValue(Iterable> monos) { return onAssembly(new MonoFirstWithValue<>(monos)); } /** * Pick the first {@link Mono} source to emit any value and replay that signal, * effectively behaving like the source that first emits an * {@link Subscriber#onNext(Object) onNext}. *

* Valued sources always "win" over an empty source (one that only emits onComplete) * or a failing source (one that only emits onError). *

* When no source can provide a value, this operator fails with a {@link NoSuchElementException} * (provided there are at least two sources). This exception has a {@link Exceptions#multiple(Throwable...) composite} * as its {@link Throwable#getCause() cause} that can be used to inspect what went wrong with each source * (so the composite has as many elements as there are sources). *

* Exceptions from failing sources are directly reflected in the composite at the index of the failing source. * For empty sources, a {@link NoSuchElementException} is added at their respective index. * One can use {@link Exceptions#unwrapMultiple(Throwable) Exceptions.unwrapMultiple(topLevel.getCause())} * to easily inspect these errors as a {@link List}. *

* Note that like in {@link #firstWithSignal(Mono[])}, an infinite source can be problematic * if no other source emits onNext. * In case the {@code first} source is already an array-based {@link #firstWithValue(Mono, Mono[])} * instance, nesting is avoided: a single new array-based instance is created with all the * sources from {@code first} plus all the {@code others} sources at the same level. *

* * * @param first the first competing source {@link Mono} * @param others the other competing sources {@link Mono} * @param The type of the element in the sources and the resulting mono * * @return a new {@link Mono} behaving like the fastest of its sources */ @SafeVarargs public static Mono firstWithValue(Mono first, Mono... others) { if (first instanceof MonoFirstWithValue) { @SuppressWarnings("unchecked") MonoFirstWithValue a = (MonoFirstWithValue) first; Mono result = a.firstValuedAdditionalSources(others); if (result != null) { return result; } } return onAssembly(new MonoFirstWithValue<>(first, others)); } /** * Expose the specified {@link Publisher} with the {@link Mono} API, and ensure it will emit 0 or 1 item. * The source emitter will be cancelled on the first `onNext`. *

* *

* {@link Hooks#onEachOperator(String, Function)} and similar assembly hooks are applied * unless the source is already a {@link Mono} (including {@link Mono} that was decorated as a {@link Flux}, * see {@link Flux#from(Publisher)}). * * @param source the {@link Publisher} source * @param the source type * * @return the next item emitted as a {@link Mono} */ public static Mono from(Publisher source) { //some sources can be considered already assembled monos //all conversion methods (from, fromDirect, wrap) must accommodate for this boolean shouldWrap = ContextPropagationSupport.shouldWrapPublisher(source); if (source instanceof Mono && !shouldWrap) { @SuppressWarnings("unchecked") Mono casted = (Mono) source; return casted; } if (source instanceof FluxSourceMono || source instanceof FluxSourceMonoFuseable) { @SuppressWarnings("unchecked") FluxFromMonoOperator wrapper = (FluxFromMonoOperator) source; @SuppressWarnings("unchecked") Mono extracted = (Mono) wrapper.source; boolean shouldWrapExtracted = ContextPropagationSupport.shouldWrapPublisher(extracted); if (!shouldWrapExtracted) { return extracted; } else { // Skip assembly hook return wrap(extracted, false); } } //we delegate to `wrap` and apply assembly hooks @SuppressWarnings("unchecked") Publisher downcasted = (Publisher) source; return onAssembly(wrap(downcasted, true)); } /** * Create a {@link Mono} producing its value using the provided {@link Callable}. If * the Callable resolves to {@code null}, the resulting Mono completes empty. * *

* *

* @param supplier {@link Callable} that will produce the value * @param type of the expected value * * @return A {@link Mono}. */ public static Mono fromCallable(Callable supplier) { return onAssembly(new MonoCallable<>(supplier)); } /** * Create a {@link Mono}, producing its value using the provided {@link CompletionStage}. * *

* *

* If the completionStage is also a {@link Future}, cancelling the Mono will cancel the future. * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to * {@code true} if you need to suppress cancellation propagation. * * @param completionStage {@link CompletionStage} that will produce a value (or a null to * complete immediately) * @param type of the expected value * @return A {@link Mono}. */ public static Mono fromCompletionStage(CompletionStage completionStage) { return onAssembly(new MonoCompletionStage<>(completionStage, false)); } /** * Create a {@link Mono} that wraps a lazily-supplied {@link CompletionStage} on subscription, * emitting the value produced by the {@link CompletionStage}. * *

* *

* If the completionStage is also a {@link Future}, cancelling the Mono will cancel the future. * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to * {@code true} if you need to suppress cancellation propagation. * * @param stageSupplier The {@link Supplier} of a {@link CompletionStage} that will produce a value (or a null to * complete immediately). This allows lazy triggering of CompletionStage-based APIs. * @param type of the expected value * @return A {@link Mono}. */ public static Mono fromCompletionStage(Supplier> stageSupplier) { return defer(() -> onAssembly(new MonoCompletionStage<>(stageSupplier.get(), false))); } /** * Convert a {@link Publisher} to a {@link Mono} without any cardinality check * (ie this method doesn't cancel the source past the first element). * Conversion transparently returns {@link Mono} sources without wrapping and otherwise * supports {@link Fuseable} sources. * Note this is an advanced interoperability operator that implies you know the * {@link Publisher} you are converting follows the {@link Mono} semantics and only * ever emits one element. *

* {@link Hooks#onEachOperator(String, Function)} and similar assembly hooks are applied * unless the source is already a {@link Mono}. * * @param source the Mono-compatible {@link Publisher} to wrap * @param type of the value emitted by the publisher * @return a wrapped {@link Mono} */ public static Mono fromDirect(Publisher source){ //some sources can be considered already assembled monos //all conversion methods (from, fromDirect, wrap) must accommodate for this boolean shouldWrap = ContextPropagationSupport.shouldWrapPublisher(source); if (source instanceof Mono && !shouldWrap) { @SuppressWarnings("unchecked") Mono m = (Mono)source; return m; } if (source instanceof FluxSourceMono || source instanceof FluxSourceMonoFuseable) { @SuppressWarnings("unchecked") FluxFromMonoOperator wrapper = (FluxFromMonoOperator) source; @SuppressWarnings("unchecked") Mono extracted = (Mono) wrapper.source; boolean shouldWrapExtracted = ContextPropagationSupport.shouldWrapPublisher(extracted); if (!shouldWrapExtracted) { return extracted; } else { // Skip assembly hook return wrap(extracted, false); } } //we delegate to `wrap` and apply assembly hooks @SuppressWarnings("unchecked") Publisher downcasted = (Publisher) source; return onAssembly(wrap(downcasted, false)); } /** * Create a {@link Mono}, producing its value using the provided {@link CompletableFuture} * and cancelling the future if the Mono gets cancelled. * *

* *

* Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to * {@code true} if you need to suppress cancellation propagation. * * @param future {@link CompletableFuture} that will produce a value (or a null to * complete immediately) * @param type of the expected value * @return A {@link Mono}. * @see #fromCompletionStage(CompletionStage) fromCompletionStage for a generalization */ public static Mono fromFuture(CompletableFuture future) { return fromFuture(future, false); } /** * Create a {@link Mono}, producing its value using the provided {@link CompletableFuture} * and optionally cancelling the future if the Mono gets cancelled (if {@code suppressCancel == false}). * *

* *

* * @param future {@link CompletableFuture} that will produce a value (or a null to complete immediately) * @param suppressCancel {@code true} to prevent cancellation of the future when the Mono is cancelled, * {@code false} otherwise (the default) * @param type of the expected value * @return A {@link Mono}. */ public static Mono fromFuture(CompletableFuture future, boolean suppressCancel) { return onAssembly(new MonoCompletionStage<>(future, suppressCancel)); } /** * Create a {@link Mono} that wraps a lazily-supplied {@link CompletableFuture} on subscription, * emitting the value produced by the future and cancelling the future if the Mono gets cancelled. * *

* *

* * @param futureSupplier The {@link Supplier} of a {@link CompletableFuture} that will produce a value * (or a null to complete immediately). This allows lazy triggering of future-based APIs. * @param type of the expected value * @return A {@link Mono}. * @see #fromCompletionStage(Supplier) fromCompletionStage for a generalization */ public static Mono fromFuture(Supplier> futureSupplier) { return fromFuture(futureSupplier, false); } /** * Create a {@link Mono} that wraps a lazily-supplied {@link CompletableFuture} on subscription, * emitting the value produced by the future and optionally cancelling the future if the Mono gets cancelled * (if {@code suppressCancel == false}). * *

* *

* * @param futureSupplier The {@link Supplier} of a {@link CompletableFuture} that will produce a value * (or a null to complete immediately). This allows lazy triggering of future-based APIs. * @param suppressCancel {@code true} to prevent cancellation of the future when the Mono is cancelled, * {@code false} otherwise (the default) * @param type of the expected value * @return A {@link Mono}. * @see #fromCompletionStage(Supplier) fromCompletionStage for a generalization */ public static Mono fromFuture(Supplier> futureSupplier, boolean suppressCancel) { return defer(() -> onAssembly(new MonoCompletionStage<>(futureSupplier.get(), suppressCancel))); } /** * Create a {@link Mono} that completes empty once the provided {@link Runnable} has * been executed. * *

* *

* @param runnable {@link Runnable} that will be executed before emitting the completion signal * * @param The generic type of the upstream, which is preserved by this operator * @return A {@link Mono}. */ public static Mono fromRunnable(Runnable runnable) { return onAssembly(new MonoRunnable<>(runnable)); } /** * Create a {@link Mono}, producing its value using the provided {@link Supplier}. If * the Supplier resolves to {@code null}, the resulting Mono completes empty. * *

* *

* @param supplier {@link Supplier} that will produce the value * @param type of the expected value * * @return A {@link Mono}. */ public static Mono fromSupplier(Supplier supplier) { return onAssembly(new MonoSupplier<>(supplier)); } /** * Create a new {@link Mono} that ignores elements from the source (dropping them), * but completes when the source completes. * *

* *

* *

Discard Support: This operator discards the element from the source. * * @param source the {@link Publisher} to ignore * @param the source type of the ignored data * * @return a new completable {@link Mono}. */ public static Mono ignoreElements(Publisher source) { return onAssembly(new MonoIgnorePublisher<>(source)); } /** * Create a new {@link Mono} that emits the specified item, which is captured at * instantiation time. * *

* *

* @param data the only item to onNext * @param the type of the produced item * * @return a {@link Mono}. */ public static Mono just(T data) { return onAssembly(new MonoJust<>(data)); } /** * Create a new {@link Mono} that emits the specified item if {@link Optional#isPresent()} otherwise only emits * onComplete. * *

* *

* @param data the {@link Optional} item to onNext or onComplete if not present * @param the type of the produced item * * @return a {@link Mono}. */ public static Mono justOrEmpty(@Nullable Optional data) { return data != null && data.isPresent() ? just(data.get()) : empty(); } /** * Create a new {@link Mono} that emits the specified item if non null otherwise only emits * onComplete. * *

* *

* @param data the item to onNext or onComplete if null * @param the type of the produced item * * @return a {@link Mono}. */ public static Mono justOrEmpty(@Nullable T data) { return data != null ? just(data) : empty(); } /** * Return a {@link Mono} that will never signal any data, error or completion signal, * essentially running indefinitely. *

* *

* @param the {@link Subscriber} type target * * @return a never completing {@link Mono} */ public static Mono never() { return MonoNever.instance(); } /** * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the * same by comparing the items emitted by each Publisher pairwise. *

* * * @param source1 the first Publisher to compare * @param source2 the second Publisher to compare * @param the type of items emitted by each Publisher * @return a Mono that emits a Boolean value that indicates whether the two sequences are the same */ public static Mono sequenceEqual(Publisher source1, Publisher source2) { return sequenceEqual(source1, source2, equalsBiPredicate(), Queues.SMALL_BUFFER_SIZE); } /** * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the * same by comparing the items emitted by each Publisher pairwise based on the results of a specified * equality function. *

* * * @param source1 the first Publisher to compare * @param source2 the second Publisher to compare * @param isEqual a function used to compare items emitted by each Publisher * @param the type of items emitted by each Publisher * @return a Mono that emits a Boolean value that indicates whether the two Publisher two sequences * are the same according to the specified function */ public static Mono sequenceEqual(Publisher source1, Publisher source2, BiPredicate isEqual) { return sequenceEqual(source1, source2, isEqual, Queues.SMALL_BUFFER_SIZE); } /** * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the * same by comparing the items emitted by each Publisher pairwise based on the results of a specified * equality function. *

* * * @param source1 the first Publisher to compare * @param source2 the second Publisher to compare * @param isEqual a function used to compare items emitted by each Publisher * @param prefetch the number of items to prefetch from the first and second source Publisher * @param the type of items emitted by each Publisher * @return a Mono that emits a Boolean value that indicates whether the two Publisher two sequences * are the same according to the specified function */ public static Mono sequenceEqual(Publisher source1, Publisher source2, BiPredicate isEqual, int prefetch) { return onAssembly(new MonoSequenceEqual<>(source1, source2, isEqual, prefetch)); } /** * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the value from a * Mono derived from the same resource and makes sure the resource is released if the * sequence terminates or the Subscriber cancels. *

*

    *
  • For eager cleanup, unlike in {@link Flux#using(Callable, Function, Consumer, boolean) Flux}, * in the case of a valued {@link Mono} the cleanup happens just before passing the value to downstream. * In all cases, exceptions raised by the eager cleanup {@link Consumer} may override the terminal event, * discarding the element if the derived {@link Mono} was valued.
  • *
  • Non-eager cleanup will drop any exception.
  • *
*

* * * @param resourceSupplier a {@link Callable} that is called on subscribe to create the resource * @param sourceSupplier a {@link Mono} factory to create the Mono depending on the created resource * @param resourceCleanup invoked on completion to clean-up the resource * @param eager set to true to clean before any signal (including onNext) is passed downstream * @param emitted type * @param resource type * * @return new {@link Mono} */ public static Mono using(Callable resourceSupplier, Function> sourceSupplier, Consumer resourceCleanup, boolean eager) { return onAssembly(new MonoUsing<>(resourceSupplier, sourceSupplier, resourceCleanup, eager)); } /** * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the value from a * Mono derived from the same resource and makes sure the resource is released if the * sequence terminates or the Subscriber cancels. *

* Unlike in {@link Flux#using(Callable, Function, Consumer) Flux}, in the case of a valued {@link Mono} the cleanup * happens just before passing the value to downstream. In all cases, exceptions raised by the cleanup * {@link Consumer} may override the terminal event, discarding the element if the derived {@link Mono} was valued. *

* * * @param resourceSupplier a {@link Callable} that is called on subscribe to create the resource * @param sourceSupplier a {@link Mono} factory to create the Mono depending on the created resource * @param resourceCleanup invoked on completion to clean-up the resource * @param emitted type * @param resource type * * @return new {@link Mono} */ public static Mono using(Callable resourceSupplier, Function> sourceSupplier, Consumer resourceCleanup) { return using(resourceSupplier, sourceSupplier, resourceCleanup, true); } /** * Uses a resource, generated by a {@link Publisher} for each individual {@link Subscriber}, * to derive a {@link Mono}. Note that all steps of the operator chain that would need the * resource to be in an open stable state need to be described inside the {@code resourceClosure} * {@link Function}. *

* Unlike in {@link Flux#usingWhen(Publisher, Function, Function) the Flux counterpart}, ALL signals are deferred * until the {@link Mono} terminates and the relevant {@link Function} generates and invokes a "cleanup" * {@link Publisher}. This is because a failure in the cleanup Publisher * must result in a lone {@code onError} signal in the downstream {@link Mono} (any potential value in the * derived {@link Mono} is discarded). Here are the various scenarios that can play out: *

    *
  • empty Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onComplete()}
  • *
  • empty Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}
  • *
  • valued Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onNext(value),onComplete()}
  • *
  • valued Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}, {@code value} is discarded
  • *
  • error(e) Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onError(e)}
  • *
  • error(e) Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}, t suppressing e
  • *
*

* *

* Note that if the resource supplying {@link Publisher} emits more than one resource, the * subsequent resources are dropped ({@link Operators#onNextDropped(Object, Context)}). If * the publisher errors AFTER having emitted one resource, the error is also silently dropped * ({@link Operators#onErrorDropped(Throwable, Context)}). * An empty completion or error without at least one onNext signal (no resource supplied) * triggers a short-circuit of the main sequence with the same terminal signal * (no cleanup is invoked). * *

Discard Support: This operator discards any source element if the {@code asyncCleanup} handler fails. * * @param resourceSupplier a {@link Publisher} that "generates" the resource, * subscribed for each subscription to the main sequence * @param resourceClosure a factory to derive a {@link Mono} from the supplied resource * @param asyncCleanup an asynchronous resource cleanup invoked when the resource * closure terminates (with onComplete, onError or cancel) * @param the type of elements emitted by the resource closure, and thus the main sequence * @param the type of the resource object * * @return a new {@link Mono} built around a "transactional" resource, with deferred emission until the * asynchronous cleanup sequence completes */ public static Mono usingWhen(Publisher resourceSupplier, Function> resourceClosure, Function> asyncCleanup) { return usingWhen(resourceSupplier, resourceClosure, asyncCleanup, (res, error) -> asyncCleanup.apply(res), asyncCleanup); } /** * Uses a resource, generated by a {@link Publisher} for each individual {@link Subscriber}, * to derive a {@link Mono}.Note that all steps of the operator chain that would need the * resource to be in an open stable state need to be described inside the {@code resourceClosure} * {@link Function}. *

* Unlike in {@link Flux#usingWhen(Publisher, Function, Function, BiFunction, Function) the Flux counterpart}, * ALL signals are deferred until the {@link Mono} terminates and the relevant {@link Function} * generates and invokes a "cleanup" {@link Publisher}. This is because a failure in the cleanup Publisher * must result in a lone {@code onError} signal in the downstream {@link Mono} (any potential value in the * derived {@link Mono} is discarded). Here are the various scenarios that can play out: *

    *
  • empty Mono, asyncComplete ends with {@code onComplete()}: downstream receives {@code onComplete()}
  • *
  • empty Mono, asyncComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}
  • *
  • valued Mono, asyncComplete ends with {@code onComplete()}: downstream receives {@code onNext(value),onComplete()}
  • *
  • valued Mono, asyncComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}, {@code value} is discarded
  • *
  • error(e) Mono, errorComplete ends with {@code onComplete()}: downstream receives {@code onError(e)}
  • *
  • error(e) Mono, errorComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}, t suppressing e
  • *
*

* *

* Individual cleanups can also be associated with mono cancellation and * error terminations: *

* *

* Note that if the resource supplying {@link Publisher} emits more than one resource, the * subsequent resources are dropped ({@link Operators#onNextDropped(Object, Context)}). If * the publisher errors AFTER having emitted one resource, the error is also silently dropped * ({@link Operators#onErrorDropped(Throwable, Context)}). * An empty completion or error without at least one onNext signal (no resource supplied) * triggers a short-circuit of the main sequence with the same terminal signal * (no cleanup is invoked). * *

Discard Support: This operator discards the element if the {@code asyncComplete} handler fails. * * @param resourceSupplier a {@link Publisher} that "generates" the resource, * subscribed for each subscription to the main sequence * @param resourceClosure a factory to derive a {@link Mono} from the supplied resource * @param asyncComplete an asynchronous resource cleanup invoked if the resource closure terminates with onComplete * @param asyncError an asynchronous resource cleanup invoked if the resource closure terminates with onError. * The terminating error is provided to the {@link BiFunction} * @param asyncCancel an asynchronous resource cleanup invoked if the resource closure is cancelled. * When {@code null}, the {@code asyncComplete} path is used instead. * @param the type of elements emitted by the resource closure, and thus the main sequence * @param the type of the resource object * * @return a new {@link Mono} built around a "transactional" resource, with several * termination path triggering asynchronous cleanup sequences * */ public static Mono usingWhen(Publisher resourceSupplier, Function> resourceClosure, Function> asyncComplete, BiFunction> asyncError, //the operator itself accepts null for asyncCancel, but we won't in the public API Function> asyncCancel) { return onAssembly(new MonoUsingWhen<>(resourceSupplier, resourceClosure, asyncComplete, asyncError, asyncCancel)); } /** * Aggregate given publishers into a new {@literal Mono} that will be fulfilled * when all of the given {@literal sources} have completed. An error will cause * pending results to be cancelled and immediate error emission to the returned {@link Mono}. *

* *

* @param sources The sources to use. * * @return a {@link Mono}. */ public static Mono when(Publisher... sources) { if (sources.length == 0) { return empty(); } if (sources.length == 1) { return empty(sources[0]); } return onAssembly(new MonoWhen(false, sources)); } /** * Aggregate given publishers into a new {@literal Mono} that will be * fulfilled when all of the given {@literal Publishers} have completed. * An error will cause pending results to be cancelled and immediate error emission * to the returned {@link Mono}. * *

* *

* * @param sources The sources to use. * * @return a {@link Mono}. */ public static Mono when(final Iterable> sources) { return onAssembly(new MonoWhen(false, sources)); } /** * Aggregate given publishers into a new {@literal Mono} that will be * fulfilled when all of the given {@literal sources} have completed. Errors from * the sources are delayed. * If several Publishers error, the exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* * @param sources The sources to use. * * @return a {@link Mono}. */ public static Mono whenDelayError(final Iterable> sources) { return onAssembly(new MonoWhen(true, sources)); } /** * Merge given publishers into a new {@literal Mono} that will be fulfilled when * all of the given {@literal sources} have completed. Errors from the sources are delayed. * If several Publishers error, the exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param sources The sources to use. * * @return a {@link Mono}. */ public static Mono whenDelayError(Publisher... sources) { if (sources.length == 0) { return empty(); } if (sources.length == 1) { return empty(sources[0]); } return onAssembly(new MonoWhen(true, sources)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple2}. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * * @return a {@link Mono}. */ public static Mono> zip(Mono p1, Mono p2) { return zip(p1, p2, Flux.tuple2Function()); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values as defined by the combinator function. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param combinator a {@link BiFunction} combinator function when both sources * complete * @param type of the value from p1 * @param type of the value from p2 * @param output value * * @return a {@link Mono}. */ public static Mono zip(Mono p1, Mono p2, BiFunction combinator) { return onAssembly(new MonoZip(false, p1, p2, combinator)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple3}. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zip(Mono p1, Mono p2, Mono p3) { return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple4}. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zip(Mono p1, Mono p2, Mono p3, Mono p4) { return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple5}. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zip(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5) { return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple6}. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param p6 The sixth upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * @param type of the value from p6 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zip(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5, Mono p6) { return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple7}. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param p6 The sixth upstream {@link Publisher} to subscribe to. * @param p7 The seventh upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * @param type of the value from p6 * @param type of the value from p7 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zip(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5, Mono p6, Mono p7) { return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple8}. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param p6 The sixth upstream {@link Publisher} to subscribe to. * @param p7 The seventh upstream {@link Publisher} to subscribe to. * @param p8 The eight upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * @param type of the value from p6 * @param type of the value from p7 * @param type of the value from p8 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zip(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5, Mono p6, Mono p7, Mono p8) { return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7, p8)); } /** * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal * Monos} have produced an item, aggregating their values according to the provided combinator function. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* *

* * @param monos The monos to use. * @param combinator the function to transform the combined array into an arbitrary * object. * @param the combined result * * @return a {@link Mono}. */ public static Mono zip(final Iterable> monos, Function combinator) { return onAssembly(new MonoZip<>(false, combinator, monos)); } /** * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal * Monos} have produced an item, aggregating their values according to the provided combinator function. * An error or empty completion of any source will cause other sources * to be cancelled and the resulting Mono to immediately error or complete, respectively. *

* *

* @param monos The monos to use. * @param combinator the function to transform the combined array into an arbitrary * object. * @param the combined result * * @return a {@link Mono}. */ public static Mono zip(Function combinator, Mono... monos) { if (monos.length == 0) { return empty(); } if (monos.length == 1) { return monos[0].map(d -> combinator.apply(new Object[]{d})); } return onAssembly(new MonoZip<>(false, combinator, monos)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple2} and delaying errors. * If a Mono source completes without value, the other source is run to completion then the * resulting {@link Mono} completes empty. * If both Monos error, the two exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zipDelayError(Mono p1, Mono p2) { return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Mono Monos} * have produced an item, aggregating their values into a {@link Tuple3} and delaying errors. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3) { return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple4} and delaying errors. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3, Mono p4) { return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple5} and delaying errors. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5) { return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple6} and delaying errors. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param p6 The sixth upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * @param type of the value from p6 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5, Mono p6) { return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple7} and delaying errors. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param p6 The sixth upstream {@link Publisher} to subscribe to. * @param p7 The seventh upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * @param type of the value from p6 * @param type of the value from p7 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5, Mono p6, Mono p7) { return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} * have produced an item, aggregating their values into a {@link Tuple8} and delaying errors. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param p1 The first upstream {@link Publisher} to subscribe to. * @param p2 The second upstream {@link Publisher} to subscribe to. * @param p3 The third upstream {@link Publisher} to subscribe to. * @param p4 The fourth upstream {@link Publisher} to subscribe to. * @param p5 The fifth upstream {@link Publisher} to subscribe to. * @param p6 The sixth upstream {@link Publisher} to subscribe to. * @param p7 The seventh upstream {@link Publisher} to subscribe to. * @param p8 The eight upstream {@link Publisher} to subscribe to. * @param type of the value from p1 * @param type of the value from p2 * @param type of the value from p3 * @param type of the value from p4 * @param type of the value from p5 * @param type of the value from p6 * @param type of the value from p7 * @param type of the value from p8 * * @return a {@link Mono}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3, Mono p4, Mono p5, Mono p6, Mono p7, Mono p8) { return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7, p8)); } /** * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal * Monos} have produced an item. Errors from the sources are delayed. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). *

* *

* * @param monos The monos to use. * @param combinator the function to transform the combined array into an arbitrary * object. * @param the combined result * * @return a {@link Mono}. */ public static Mono zipDelayError(final Iterable> monos, Function combinator) { return onAssembly(new MonoZip<>(true, combinator, monos)); } /** * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the * given {@literal Monos} have produced an item, aggregating their values according to * the provided combinator function and delaying errors. * If a Mono source completes without value, all other sources are run to completion then * the resulting {@link Mono} completes empty. * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). * *

* *

* @param monos The monos to use. * @param combinator the function to transform the combined array into an arbitrary * object. * @param the combined result * * @return a combined {@link Mono}. */ public static Mono zipDelayError(Function combinator, Mono... monos) { if (monos.length == 0) { return empty(); } if (monos.length == 1) { return monos[0].map(d -> combinator.apply(new Object[]{d})); } return onAssembly(new MonoZip<>(true, combinator, monos)); } // ============================================================================================================== // Operators // ============================================================================================================== /** * Transform this {@link Mono} into a target type. * *

	 * {@code mono.as(Flux::from).subscribe() }
	 * 
* * @param transformer the {@link Function} to immediately map this {@link Mono} * into a target type * @param

the returned instance type * * @return the {@link Mono} transformed to an instance of P * @see #transformDeferred(Function) transformDeferred(Function) for a lazy transformation of Mono */ public final

P as(Function, P> transformer) { return transformer.apply(this); } /** * Join the termination signals from this mono and another source into the returned * void mono * *

* *

* @param other the {@link Publisher} to wait for * complete * @return a new combined Mono * @see #when */ public final Mono and(Publisher other) { if (this instanceof MonoWhen) { @SuppressWarnings("unchecked") MonoWhen o = (MonoWhen) this; Mono result = o.whenAdditionalSource(other); if (result != null) { return result; } } return when(this, other); } /** * Subscribe to this {@link Mono} and block indefinitely until a next signal is * received. Returns that value, or null if the Mono completes empty. In case the Mono * errors, the original exception is thrown (wrapped in a {@link RuntimeException} if * it was a checked exception). * *

* *

* Note that each block() will trigger a new subscription: in other words, the result * might miss signal from hot publishers. * * @return T the result */ @Nullable public T block() { Context context = ContextPropagationSupport.shouldPropagateContextToThreadLocals() ? ContextPropagation.contextCaptureToEmpty() : Context.empty(); BlockingMonoSubscriber subscriber = new BlockingMonoSubscriber<>(context); subscribe((Subscriber) subscriber); return subscriber.blockingGet(); } /** * Subscribe to this {@link Mono} and block until a next signal is * received or a timeout expires. Returns that value, or null if the Mono completes * empty. In case the Mono errors, the original exception is thrown (wrapped in a * {@link RuntimeException} if it was a checked exception). * If the provided timeout expires, a {@link RuntimeException} is thrown. * *

* *

* Note that each block() will trigger a new subscription: in other words, the result * might miss signal from hot publishers. * * @param timeout maximum time period to wait for before raising a {@link RuntimeException} * * @return T the result */ @Nullable public T block(Duration timeout) { Context context = ContextPropagationSupport.shouldPropagateContextToThreadLocals() ? ContextPropagation.contextCaptureToEmpty() : Context.empty(); BlockingMonoSubscriber subscriber = new BlockingMonoSubscriber<>(context); subscribe((Subscriber) subscriber); return subscriber.blockingGet(timeout.toNanos(), TimeUnit.NANOSECONDS); } /** * Subscribe to this {@link Mono} and block indefinitely until a next signal is * received or the Mono completes empty. Returns an {@link Optional}, which can be used * to replace the empty case with an Exception via {@link Optional#orElseThrow(Supplier)}. * In case the Mono itself errors, the original exception is thrown (wrapped in a * {@link RuntimeException} if it was a checked exception). * *

* *

* Note that each blockOptional() will trigger a new subscription: in other words, the result * might miss signal from hot publishers. * * @return T the result */ public Optional blockOptional() { Context context = ContextPropagationSupport.shouldPropagateContextToThreadLocals() ? ContextPropagation.contextCaptureToEmpty() : Context.empty(); BlockingOptionalMonoSubscriber subscriber = new BlockingOptionalMonoSubscriber<>(context); subscribe((Subscriber) subscriber); return subscriber.blockingGet(); } /** * Subscribe to this {@link Mono} and block until a next signal is * received, the Mono completes empty or a timeout expires. Returns an {@link Optional} * for the first two cases, which can be used to replace the empty case with an * Exception via {@link Optional#orElseThrow(Supplier)}. * In case the Mono itself errors, the original exception is thrown (wrapped in a * {@link RuntimeException} if it was a checked exception). * If the provided timeout expires, a {@link RuntimeException} is thrown. * *

* *

* Note that each block() will trigger a new subscription: in other words, the result * might miss signal from hot publishers. * * @param timeout maximum time period to wait for before raising a {@link RuntimeException} * * @return T the result */ public Optional blockOptional(Duration timeout) { Context context = ContextPropagationSupport.shouldPropagateContextToThreadLocals() ? ContextPropagation.contextCaptureToEmpty() : Context.empty(); BlockingOptionalMonoSubscriber subscriber = new BlockingOptionalMonoSubscriber<>(context); subscribe((Subscriber) subscriber); return subscriber.blockingGet(timeout.toNanos(), TimeUnit.NANOSECONDS); } /** * Cast the current {@link Mono} produced type into a target produced type. * *

* * * @param the {@link Mono} output type * @param clazz the target type to cast to * * @return a casted {@link Mono} */ public final Mono cast(Class clazz) { Objects.requireNonNull(clazz, "clazz"); return map(clazz::cast); } /** * Turn this {@link Mono} into a hot source and cache last emitted signals for further {@link Subscriber}. * Completion and Error will also be replayed. *

* *

* Once the first subscription is made to this {@link Mono}, the source is subscribed to and * the signal will be cached, indefinitely. This process cannot be cancelled. *

* In the face of multiple concurrent subscriptions, this operator ensures that only one * subscription is made to the source. * * @return a replaying {@link Mono} */ public final Mono cache() { return onAssembly(new MonoCacheTime<>(this)); } /** * Turn this {@link Mono} into a hot source and cache last emitted signals for further * {@link Subscriber}, with an expiry timeout. *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription. *

* *

* Cache loading (ie. subscription to the source) is triggered atomically by the first * subscription to an uninitialized or expired cache, which guarantees that a single * cache load happens at a time (and other subscriptions will get notified of the newly * cached value when it arrives). * * @return a replaying {@link Mono} */ public final Mono cache(Duration ttl) { return cache(ttl, Schedulers.parallel()); } /** * Turn this {@link Mono} into a hot source and cache last emitted signals for further * {@link Subscriber}, with an expiry timeout. *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription. *

* *

* Cache loading (ie. subscription to the source) is triggered atomically by the first * subscription to an uninitialized or expired cache, which guarantees that a single * cache load happens at a time (and other subscriptions will get notified of the newly * cached value when it arrives). * * @param ttl Time-to-live for each cached item and post termination. * @param timer the {@link Scheduler} on which to measure the duration. * * @return a replaying {@link Mono} */ public final Mono cache(Duration ttl, Scheduler timer) { return onAssembly(new MonoCacheTime<>(this, ttl, timer)); } /** * Turn this {@link Mono} into a hot source and cache last emitted signal for further * {@link Subscriber}, with an expiry timeout (TTL) that depends on said signal. * A TTL of {@link Long#MAX_VALUE} milliseconds is interpreted as indefinite caching of * the signal (no cache cleanup is scheduled, so the signal is retained as long as this * {@link Mono} is not garbage collected). *

* Empty completion and Error will also be replayed according to their respective TTL, * so transient errors can be "retried" by letting the {@link Function} return * {@link Duration#ZERO}. Such a transient exception would then be propagated to the first * subscriber but the following subscribers would trigger a new source subscription. *

* Exceptions in the TTL generators themselves are processed like the {@link Duration#ZERO} * case, except the original signal is {@link Exceptions#addSuppressed(Throwable, Throwable) suppressed} * (in case of onError) or {@link Hooks#onNextDropped(Consumer) dropped} * (in case of onNext). *

* Note that subscribers that come in perfectly simultaneously could receive the same * cached signal even if the TTL is set to zero. *

* Cache loading (ie. subscription to the source) is triggered atomically by the first * subscription to an uninitialized or expired cache, which guarantees that a single * cache load happens at a time (and other subscriptions will get notified of the newly * cached value when it arrives). * * @param ttlForValue the TTL-generating {@link Function} invoked when source is valued * @param ttlForError the TTL-generating {@link Function} invoked when source is erroring * @param ttlForEmpty the TTL-generating {@link Supplier} invoked when source is empty * @return a replaying {@link Mono} */ public final Mono cache(Function ttlForValue, Function ttlForError, Supplier ttlForEmpty) { return cache(ttlForValue, ttlForError, ttlForEmpty, Schedulers.parallel()); } /** * Turn this {@link Mono} into a hot source and cache last emitted signal for further * {@link Subscriber}, with an expiry timeout (TTL) that depends on said signal. * A TTL of {@link Long#MAX_VALUE} milliseconds is interpreted as indefinite caching of * the signal (no cache cleanup is scheduled, so the signal is retained as long as this * {@link Mono} is not garbage collected). *

* Empty completion and Error will also be replayed according to their respective TTL, * so transient errors can be "retried" by letting the {@link Function} return * {@link Duration#ZERO}. Such a transient exception would then be propagated to the first * subscriber but the following subscribers would trigger a new source subscription. *

* Exceptions in the TTL generators themselves are processed like the {@link Duration#ZERO} * case, except the original signal is {@link Exceptions#addSuppressed(Throwable, Throwable) suppressed} * (in case of onError) or {@link Hooks#onNextDropped(Consumer) dropped} * (in case of onNext). *

* Note that subscribers that come in perfectly simultaneously could receive the same * cached signal even if the TTL is set to zero. *

* Cache loading (ie. subscription to the source) is triggered atomically by the first * subscription to an uninitialized or expired cache, which guarantees that a single * cache load happens at a time (and other subscriptions will get notified of the newly * cached value when it arrives). * * @param ttlForValue the TTL-generating {@link Function} invoked when source is valued * @param ttlForError the TTL-generating {@link Function} invoked when source is erroring * @param ttlForEmpty the TTL-generating {@link Supplier} invoked when source is empty * @param timer the {@link Scheduler} on which to measure the duration. * @return a replaying {@link Mono} */ public final Mono cache(Function ttlForValue, Function ttlForError, Supplier ttlForEmpty, Scheduler timer) { return onAssembly(new MonoCacheTime<>(this, ttlForValue, ttlForError, ttlForEmpty, timer)); } /** * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, * while allowing invalidation by verifying the cached value against the given {@link Predicate} each time a late * subscription occurs. * Note that the {@link Predicate} is only evaluated if the cache is currently populated, ie. it is not applied * upon receiving the source {@link Subscriber#onNext(Object) onNext} signal. * For late subscribers, if the predicate returns {@code true} the cache is invalidated and a new subscription is made * to the source in an effort to refresh the cache with a more up-to-date value to be passed to the new subscriber. *

* The predicate is not strictly evaluated once per downstream subscriber. Rather, subscriptions happening in concurrent * batches will trigger a single evaluation of the predicate. Similarly, a batch of subscriptions happening before * the cache is populated (ie. before this operator receives an onNext signal after an invalidation) will always * receive the incoming value without going through the {@link Predicate}. The predicate is only triggered by * subscribers that come in AFTER the cache is populated. Therefore, it is possible that pre-population subscribers * receive an "invalid" value, especially if the object can switch from a valid to an invalid state in a short amount * of time (eg. between creation, cache population and propagation to the downstream subscriber(s)). *

* If the cached value needs to be discarded in case of invalidation, the recommended way is to do so in the predicate * directly. Note that some downstream subscribers might still be using or storing the value, for example if they * haven't requested anything yet. *

* As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} * if one wants to only consider empty sources or error sources). *

* Predicate is applied differently depending on whether the cache is populated or not: *

    *
  • IF EMPTY *
    • first incoming subscriber creates a new COORDINATOR and adds itself
    *
  • *
  • IF COORDINATOR *
      *
    1. each incoming subscriber is added to the current "batch" (COORDINATOR)
    2. *
    3. once the value is received, the predicate is applied ONCE *
        *
      1. mismatch: all the batch is terminated with an error * -> we're back to init state, next subscriber will trigger a new coordinator and a new subscription
      2. *
      3. ok: all the batch is completed with the value -> cache is now POPULATED
      4. *
      *
    4. *
    *
  • *
  • IF POPULATED *
      *
    1. each incoming subscriber causes the predicate to apply
    2. *
    3. if ok: complete that subscriber with the value
    4. *
    5. if mismatch, swap the current POPULATED with a new COORDINATOR and add the subscriber to that coordinator
    6. *
    7. imagining a race between sub1 and sub2: *
        *
      1. OK NOK will naturally lead to sub1 completing and sub2 being put on wait inside a new COORDINATOR
      2. *
      3. NOK NOK will race swap of POPULATED with COORDINATOR1 and COORDINATOR2 respectively *
          *
        1. if sub1 swaps, sub2 will dismiss the COORDINATOR2 it failed to swap and loop back, see COORDINATOR1 and add itself
        2. *
        3. if sub2 swaps, the reverse happens
        4. *
        5. if value is populated in the time it takes for sub2 to loop back, sub2 sees a value and triggers the predicate again (hopefully passing)
        6. *
        *
      4. *
      *
    8. *
    *
  • *
*

* Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. *

* When cancelling a COORDINATOR-issued subscription: *

    *
  1. removes itself from batch
  2. *
  3. if 0 subscribers remaining *
      *
    1. swap COORDINATOR with EMPTY
    2. *
    3. COORDINATOR cancels its source
    4. *
    *
  4. *
*

* The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). * * @param invalidationPredicate the {@link Predicate} used for cache invalidation. Returning {@code true} means the value is invalid and should be * removed from the cache. * @return a new cached {@link Mono} which can be invalidated */ public final Mono cacheInvalidateIf(Predicate invalidationPredicate) { return onAssembly(new MonoCacheInvalidateIf<>(this, invalidationPredicate)); } /** * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, * while allowing invalidation via a {@link Mono Mono<Void>} companion trigger generated from the currently * cached value. *

* As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} * if one wants to only consider empty sources or error sources). The exception is still propagated to the subscribers * that have accumulated between the time the source has been subscribed to and the time the onError/onComplete terminal * signal is received. An empty source is turned into a {@link NoSuchElementException} onError. *

* Completion of the trigger will invalidate the cached element, so the next subscriber that comes in will trigger * a new subscription to the source, re-populating the cache and re-creating a new trigger out of that value. *

*

    *
  • * If the trigger completes with an error, all registered subscribers are terminated with the same error. *
  • *
  • * If all the subscribers are cancelled before the cache is populated (ie. an attempt to * cache a {@link Mono#never()}), the source subscription is cancelled. *
  • *
  • * Cancelling a downstream subscriber once the cache has been populated is not necessarily relevant, * as the value will be immediately replayed on subscription, which usually means within onSubscribe (so * earlier than any cancellation can happen). That said the operator will make best efforts to detect such * cancellations and avoid propagating the value to these subscribers. *
  • *
*

* If the cached value needs to be discarded in case of invalidation, use the {@link #cacheInvalidateWhen(Function, Consumer)} version. * Note that some downstream subscribers might still be using or storing the value, for example if they * haven't requested anything yet. *

* Trigger is generated only after a subscribers in the COORDINATOR have received the value, and only once. * The only way to get out of the POPULATED state is to use the trigger, so there cannot be multiple trigger subscriptions, nor concurrent triggering. *

* Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. *

* When cancelling a COORDINATOR-issued subscription: *

    *
  1. removes itself from batch
  2. *
  3. if 0 subscribers remaining *
      *
    1. swap COORDINATOR with EMPTY
    2. *
    3. COORDINATOR cancels its source
    4. *
    *
  4. *
*

* The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). * * @param invalidationTriggerGenerator the {@link Function} that generates new {@link Mono Mono<Void>} triggers * used for invalidation * @return a new cached {@link Mono} which can be invalidated */ public final Mono cacheInvalidateWhen(Function> invalidationTriggerGenerator) { return onAssembly(new MonoCacheInvalidateWhen<>(this, invalidationTriggerGenerator, null)); } /** * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, * while allowing invalidation via a {@link Mono Mono<Void>} companion trigger generated from the currently * cached value. *

* As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} * if one wants to only consider empty sources or error sources). The exception is still propagated to the subscribers * that have accumulated between the time the source has been subscribed to and the time the onError/onComplete terminal * signal is received. An empty source is turned into a {@link NoSuchElementException} onError. *

* Completion of the trigger will invalidate the cached element, so the next subscriber that comes in will trigger * a new subscription to the source, re-populating the cache and re-creating a new trigger out of that value. *

*

    *
  • * If the trigger completes with an error, all registered subscribers are terminated with the same error. *
  • *
  • * If all the subscribers are cancelled before the cache is populated (ie. an attempt to * cache a {@link Mono#never()}), the source subscription is cancelled. *
  • *
  • * Cancelling a downstream subscriber once the cache has been populated is not necessarily relevant, * as the value will be immediately replayed on subscription, which usually means within onSubscribe (so * earlier than any cancellation can happen). That said the operator will make best efforts to detect such * cancellations and avoid propagating the value to these subscribers. *
  • *
*

* Once a cached value is invalidated, it is passed to the provided {@link Consumer} (which MUST complete normally). * Note that some downstream subscribers might still be using or storing the value, for example if they * haven't requested anything yet. *

* Trigger is generated only after a subscribers in the COORDINATOR have received the value, and only once. * The only way to get out of the POPULATED state is to use the trigger, so there cannot be multiple trigger subscriptions, nor concurrent triggering. *

* Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. *

* When cancelling a COORDINATOR-issued subscription: *

    *
  1. removes itself from batch
  2. *
  3. if 0 subscribers remaining *
      *
    1. swap COORDINATOR with EMPTY
    2. *
    3. COORDINATOR cancels its source
    4. *
    *
  4. *
*

* The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). * * @param invalidationTriggerGenerator the {@link Function} that generates new {@link Mono Mono<Void>} triggers * used for invalidation * @param onInvalidate the {@link Consumer} that will be applied to cached value upon invalidation * @return a new cached {@link Mono} which can be invalidated */ public final Mono cacheInvalidateWhen(Function> invalidationTriggerGenerator, Consumer onInvalidate) { return onAssembly(new MonoCacheInvalidateWhen<>(this, invalidationTriggerGenerator, onInvalidate)); } /** * Prepare this {@link Mono} so that subscribers will cancel from it on a * specified * {@link Scheduler}. * *

* * * @param scheduler the {@link Scheduler} to signal cancel on * * @return a scheduled cancel {@link Mono} */ public final Mono cancelOn(Scheduler scheduler) { return onAssembly(new MonoCancelOn<>(this, scheduler)); } /** * Activate traceback (full assembly tracing) for this particular {@link Mono}, in case of an error * upstream of the checkpoint. Tracing incurs the cost of an exception stack trace * creation. *

* It should be placed towards the end of the reactive chain, as errors * triggered downstream of it cannot be observed and augmented with assembly trace. *

* The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback * would appear as a component of the composite. In any case, the traceback nature can be detected via * {@link Exceptions#isTraceback(Throwable)}. * * @return the assembly tracing {@link Mono} */ public final Mono checkpoint() { return checkpoint(null, true); } /** * Activate traceback (assembly marker) for this particular {@link Mono} by giving it a description that * will be reflected in the assembly traceback in case of an error upstream of the * checkpoint. Note that unlike {@link #checkpoint()}, this doesn't create a * filled stack trace, avoiding the main cost of the operator. * However, as a trade-off the description must be unique enough for the user to find * out where this Mono was assembled. If you only want a generic description, and * still rely on the stack trace to find the assembly site, use the * {@link #checkpoint(String, boolean)} variant. *

* It should be placed towards the end of the reactive chain, as errors * triggered downstream of it cannot be observed and augmented with assembly trace. *

* The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback * would appear as a component of the composite. In any case, the traceback nature can be detected via * {@link Exceptions#isTraceback(Throwable)}. * * @param description a unique enough description to include in the light assembly traceback. * @return the assembly marked {@link Mono} */ public final Mono checkpoint(String description) { return checkpoint(Objects.requireNonNull(description), false); } /** * Activate traceback (full assembly tracing or the lighter assembly marking depending on the * {@code forceStackTrace} option). *

* By setting the {@code forceStackTrace} parameter to {@literal true}, activate assembly * tracing for this particular {@link Mono} and give it a description that * will be reflected in the assembly traceback in case of an error upstream of the * checkpoint. Note that unlike {@link #checkpoint(String)}, this will incur * the cost of an exception stack trace creation. The description could for * example be a meaningful name for the assembled mono or a wider correlation ID, * since the stack trace will always provide enough information to locate where this * Flux was assembled. *

* By setting {@code forceStackTrace} to {@literal false}, behaves like * {@link #checkpoint(String)} and is subject to the same caveat in choosing the * description. *

* It should be placed towards the end of the reactive chain, as errors * triggered downstream of it cannot be observed and augmented with assembly marker. *

* The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback * would appear as a component of the composite. In any case, the traceback nature can be detected via * {@link Exceptions#isTraceback(Throwable)}. * * @param description a description (must be unique enough if forceStackTrace is set * to false). * @param forceStackTrace false to make a light checkpoint without a stacktrace, true * to use a stack trace. * @return the assembly marked {@link Mono}. */ public final Mono checkpoint(@Nullable String description, boolean forceStackTrace) { final AssemblySnapshot stacktrace; if (!forceStackTrace) { stacktrace = new CheckpointLightSnapshot(description); } else { stacktrace = new CheckpointHeavySnapshot(description, Traces.callSiteSupplierFactory.get()); } return new MonoOnAssembly<>(this, stacktrace); } /** * Concatenate emissions of this {@link Mono} with the provided {@link Publisher} * (no interleave). *

* * * @param other the {@link Publisher} sequence to concat after this {@link Flux} * * @return a concatenated {@link Flux} */ public final Flux concatWith(Publisher other) { return Flux.concat(this, other); } /** * If context-propagation library * is on the classpath, this is a convenience shortcut to capture thread local values during the * subscription phase and put them in the {@link Context} that is visible upstream of this operator. *

* As a result this operator should generally be used as close as possible to the end of * the chain / subscription point. *

* If the {@link ContextView} visible upstream is not empty, a small subset of operators will automatically * restore the context snapshot ({@link #handle(BiConsumer) handle}, {@link #tap(SignalListenerFactory) tap}). * If context-propagation is not available at runtime, this operator simply returns the current {@link Mono} * instance. * * @return a new {@link Flux} where context-propagation API has been used to capture entries and * inject them into the {@link Context} * @see #handle(BiConsumer) * @see #tap(SignalListenerFactory) */ public final Mono contextCapture() { if (!ContextPropagationSupport.isContextPropagationAvailable()) { return this; } if (ContextPropagationSupport.propagateContextToThreadLocals) { return onAssembly(new MonoContextWriteRestoringThreadLocals<>( this, ContextPropagation.contextCapture() )); } return onAssembly(new MonoContextWrite<>(this, ContextPropagation.contextCapture())); } /** * Enrich the {@link Context} visible from downstream for the benefit of upstream * operators, by making all values from the provided {@link ContextView} visible on top * of pairs from downstream. *

* A {@link Context} (and its {@link ContextView}) is tied to a given subscription * and is read by querying the downstream {@link Subscriber}. {@link Subscriber} that * don't enrich the context instead access their own downstream's context. As a result, * this operator conceptually enriches a {@link Context} coming from under it in the chain * (downstream, by default an empty one) and makes the new enriched {@link Context} * visible to operators above it in the chain. * * @param contextToAppend the {@link ContextView} to merge with the downstream {@link Context}, * resulting in a new more complete {@link Context} that will be visible from upstream. * * @return a contextualized {@link Mono} * @see ContextView */ public final Mono contextWrite(ContextView contextToAppend) { return contextWrite(c -> c.putAll(contextToAppend)); } /** * Enrich the {@link Context} visible from downstream for the benefit of upstream * operators, by applying a {@link Function} to the downstream {@link Context}. *

* The {@link Function} takes a {@link Context} for convenience, allowing to easily * call {@link Context#put(Object, Object) write APIs} to return a new {@link Context}. *

* A {@link Context} (and its {@link ContextView}) is tied to a given subscription * and is read by querying the downstream {@link Subscriber}. {@link Subscriber} that * don't enrich the context instead access their own downstream's context. As a result, * this operator conceptually enriches a {@link Context} coming from under it in the chain * (downstream, by default an empty one) and makes the new enriched {@link Context} * visible to operators above it in the chain. * * @param contextModifier the {@link Function} to apply to the downstream {@link Context}, * resulting in a new more complete {@link Context} that will be visible from upstream. * * @return a contextualized {@link Mono} * @see Context */ public final Mono contextWrite(Function contextModifier) { if (ContextPropagationSupport.shouldPropagateContextToThreadLocals()) { return onAssembly(new MonoContextWriteRestoringThreadLocals<>( this, contextModifier )); } return onAssembly(new MonoContextWrite<>(this, contextModifier)); } /** * Provide a default single value if this mono is completed without any data * *

* *

* @param defaultV the alternate value if this sequence is empty * * @return a new {@link Mono} * * @see Flux#defaultIfEmpty(Object) */ public final Mono defaultIfEmpty(T defaultV) { if (this instanceof Fuseable.ScalarCallable) { try { T v = block(); if (v == null) { return Mono.just(defaultV); } } catch (Throwable e) { //leave MonoError returns as this } return this; } return onAssembly(new MonoDefaultIfEmpty<>(this, defaultV)); } /** * Delay this {@link Mono} element ({@link Subscriber#onNext} signal) by a given * duration. Empty Monos or error signals are not delayed. * *

* * *

* Note that the scheduler on which the Mono chain continues execution will be the * {@link Schedulers#parallel() parallel} scheduler if the mono is valued, or the * current scheduler if the mono completes empty or errors. * * @param delay duration by which to delay the {@link Subscriber#onNext} signal * @return a delayed {@link Mono} */ public final Mono delayElement(Duration delay) { return delayElement(delay, Schedulers.parallel()); } /** * Delay this {@link Mono} element ({@link Subscriber#onNext} signal) by a given * {@link Duration}, on a particular {@link Scheduler}. Empty monos or error signals are not delayed. * *

* * *

* Note that the scheduler on which the mono chain continues execution will be the * scheduler provided if the mono is valued, or the current scheduler if the mono * completes empty or errors. * * @param delay {@link Duration} by which to delay the {@link Subscriber#onNext} signal * @param timer a time-capable {@link Scheduler} instance to delay the value signal on * @return a delayed {@link Mono} */ public final Mono delayElement(Duration delay, Scheduler timer) { return onAssembly(new MonoDelayElement<>(this, delay.toNanos(), TimeUnit.NANOSECONDS, timer)); } /** * Subscribe to this {@link Mono} and another {@link Publisher} that is generated from * this Mono's element and which will be used as a trigger for relaying said element. *

* That is to say, the resulting {@link Mono} delays until this Mono's element is * emitted, generates a trigger Publisher and then delays again until the trigger * Publisher terminates. *

* Note that contiguous calls to all delayUntil are fused together. * The triggers are generated and subscribed to in sequence, once the previous trigger * completes. Error is propagated immediately * downstream. In both cases, an error in the source is immediately propagated. *

* * * @param triggerProvider a {@link Function} that maps this Mono's value into a * {@link Publisher} whose termination will trigger relaying the value. * * @return this Mono, but delayed until the derived publisher terminates. */ public final Mono delayUntil(Function> triggerProvider) { Objects.requireNonNull(triggerProvider, "triggerProvider required"); if (this instanceof MonoDelayUntil) { return ((MonoDelayUntil) this).copyWithNewTriggerGenerator(false,triggerProvider); } return onAssembly(new MonoDelayUntil<>(this, triggerProvider)); } /** * Delay the {@link Mono#subscribe(Subscriber) subscription} to this {@link Mono} source until the given * period elapses. * *

* * * @param delay duration before subscribing this {@link Mono} * * @return a delayed {@link Mono} * */ public final Mono delaySubscription(Duration delay) { return delaySubscription(delay, Schedulers.parallel()); } /** * Delay the {@link Mono#subscribe(Subscriber) subscription} to this {@link Mono} source until the given * {@link Duration} elapses. * *

* * * @param delay {@link Duration} before subscribing this {@link Mono} * @param timer a time-capable {@link Scheduler} instance to run on * * @return a delayed {@link Mono} * */ public final Mono delaySubscription(Duration delay, Scheduler timer) { return delaySubscription(Mono.delay(delay, timer)); } /** * Delay the subscription to this {@link Mono} until another {@link Publisher} * signals a value or completes. * *

* * * @param subscriptionDelay a * {@link Publisher} to signal by next or complete this {@link Mono#subscribe(Subscriber)} * @param the other source type * * @return a delayed {@link Mono} * */ public final Mono delaySubscription(Publisher subscriptionDelay) { return onAssembly(new MonoDelaySubscription<>(this, subscriptionDelay)); } /** * An operator working only if this {@link Mono} emits onNext, onError or onComplete {@link Signal} * instances, transforming these {@link #materialize() materialized} signals into * real signals on the {@link Subscriber}. * The error {@link Signal} will trigger onError and complete {@link Signal} will trigger * onComplete. * *

* * * @param the dematerialized type * @return a dematerialized {@link Mono} * @see #materialize() */ public final Mono dematerialize() { @SuppressWarnings("unchecked") Mono> thiz = (Mono>) this; return onAssembly(new MonoDematerialize<>(thiz)); } /** * Add behavior (side-effect) triggered after the {@link Mono} terminates, either by * completing downstream successfully or with an error. *

* *

* The relevant signal is propagated downstream, then the {@link Runnable} is executed. * * @param afterTerminate the callback to call after {@link Subscriber#onComplete} or {@link Subscriber#onError} * * @return an observed {@link Mono} */ public final Mono doAfterTerminate(Runnable afterTerminate) { Objects.requireNonNull(afterTerminate, "afterTerminate"); return onAssembly(new MonoPeekTerminal<>(this, null, null, (s, e) -> afterTerminate.run())); } /** * Add behavior (side-effect) triggered before the {@link Mono} is * subscribed to, which should be the first event after assembly time. *

* *

* Note that when several {@link #doFirst(Runnable)} operators are used anywhere in a * chain of operators, their order of execution is reversed compared to the declaration * order (as subscribe signal flows backward, from the ultimate subscriber to the source * publisher): *


	 * Mono.just(1v)
	 *     .doFirst(() -> System.out.println("three"))
	 *     .doFirst(() -> System.out.println("two"))
	 *     .doFirst(() -> System.out.println("one"));
	 * //would print one two three
	 * 
	 * 
*

* In case the {@link Runnable} throws an exception, said exception will be directly * propagated to the subscribing {@link Subscriber} along with a no-op {@link Subscription}, * similarly to what {@link #error(Throwable)} does. Otherwise, after the handler has * executed, the {@link Subscriber} is directly subscribed to the original source * {@link Mono} ({@code this}). *

* This side-effect method provides stronger first guarantees compared to * {@link #doOnSubscribe(Consumer)}, which is triggered once the {@link Subscription} * has been set up and passed to the {@link Subscriber}. * * @param onFirst the callback to execute before the {@link Mono} is subscribed to * @return an observed {@link Mono} */ public final Mono doFirst(Runnable onFirst) { Objects.requireNonNull(onFirst, "onFirst"); if (this instanceof Fuseable) { return onAssembly(new MonoDoFirstFuseable<>(this, onFirst)); } return onAssembly(new MonoDoFirst<>(this, onFirst)); } /** * Add behavior triggering after the {@link Mono} terminates for any reason, * including cancellation. The terminating event ({@link SignalType#ON_COMPLETE}, * {@link SignalType#ON_ERROR} and {@link SignalType#CANCEL}) is passed to the consumer, * which is executed after the signal has been passed downstream. *

* Note that the fact that the signal is propagated downstream before the callback is * executed means that several doFinally in a row will be executed in * reverse order. If you want to assert the execution of the callback * please keep in mind that the Mono will complete before it is executed, so its * effect might not be visible immediately after eg. a {@link #block()}. *

* * * * @param onFinally the callback to execute after a terminal signal (complete, error * or cancel) * @return an observed {@link Mono} */ public final Mono doFinally(Consumer onFinally) { Objects.requireNonNull(onFinally, "onFinally"); return onAssembly(new MonoDoFinally<>(this, onFinally)); } /** * Add behavior triggered when the {@link Mono} is cancelled. *

* *

* The handler is executed first, then the cancel signal is propagated upstream * to the source. * * @param onCancel the callback to call on {@link Subscription#cancel()} * * @return a new {@link Mono} */ public final Mono doOnCancel(Runnable onCancel) { Objects.requireNonNull(onCancel, "onCancel"); return doOnSignal(this, null, null, null, onCancel); } /** * Potentially modify the behavior of the whole chain of operators upstream of this one to * conditionally clean up elements that get discarded by these operators. *

* The {@code discardHook} MUST be idempotent and safe to use on any instance of the desired * type. * Calls to this method are additive, and the order of invocation of the {@code discardHook} * is the same as the order of declaration (calling {@code .filter(...).doOnDiscard(first).doOnDiscard(second)} * will let the filter invoke {@code first} then {@code second} handlers). *

* Two main categories of discarding operators exist: *

    *
  • filtering operators, dropping some source elements as part of their designed behavior
  • *
  • operators that prefetch a few elements and keep them around pending a request, but get cancelled/in error
  • *
* WARNING: Not all operators support this instruction. The ones that do are identified in the javadoc by * the presence of a Discard Support section. * * @param type the {@link Class} of elements in the upstream chain of operators that * this cleanup hook should take into account. * @param discardHook a {@link Consumer} of elements in the upstream chain of operators * that performs the cleanup. * @return a {@link Mono} that cleans up matching elements that get discarded upstream of it. */ public final Mono doOnDiscard(final Class type, final Consumer discardHook) { return contextWrite(Operators.discardLocalAdapter(type, discardHook)); } /** * Add behavior triggered when the {@link Mono} emits a data successfully. * *

* *

* The {@link Consumer} is executed first, then the onNext signal is propagated * downstream. * * @param onNext the callback to call on {@link Subscriber#onNext} * * @return a new {@link Mono} */ public final Mono doOnNext(Consumer onNext) { Objects.requireNonNull(onNext, "onNext"); return doOnSignal(this, null, onNext, null, null); } /** * Add behavior triggered as soon as the {@link Mono} can be considered to have completed successfully. * The value passed to the {@link Consumer} reflects the type of completion: * *

    *
  • null : completed without data. handler is executed right before onComplete is propagated downstream
  • *
  • T: completed with data. handler is executed right before onNext is propagated downstream
  • *
* *

* *

* The {@link Consumer} is executed before propagating either onNext or onComplete downstream. * * @param onSuccess the callback to call on, argument is null if the {@link Mono} * completes without data * {@link Subscriber#onNext} or {@link Subscriber#onComplete} without preceding {@link Subscriber#onNext} * * @return a new {@link Mono} */ public final Mono doOnSuccess(Consumer onSuccess) { Objects.requireNonNull(onSuccess, "onSuccess"); return doOnTerminalSignal(this, onSuccess, null, null); } /** * Add behavior triggered when the {@link Mono} emits an item, fails with an error * or completes successfully. All these events are represented as a {@link Signal} * that is passed to the side-effect callback. Note that this is an advanced operator, * typically used for monitoring of a Mono. * These {@link Signal} have a {@link Context} associated to them. *

* *

* The {@link Consumer} is executed first, then the relevant signal is propagated * downstream. * * @param signalConsumer the mandatory callback to call on * {@link Subscriber#onNext(Object)}, {@link Subscriber#onError(Throwable)} and * {@link Subscriber#onComplete()} * @return an observed {@link Mono} * @see #doOnNext(Consumer) * @see #doOnError(Consumer) * @see #materialize() * @see Signal */ public final Mono doOnEach(Consumer> signalConsumer) { Objects.requireNonNull(signalConsumer, "signalConsumer"); if (this instanceof Fuseable) { return onAssembly(new MonoDoOnEachFuseable<>(this, signalConsumer)); } return onAssembly(new MonoDoOnEach<>(this, signalConsumer)); } /** * Add behavior triggered when the {@link Mono} completes with an error. * *

* *

* The {@link Consumer} is executed first, then the onError signal is propagated * downstream. * * @param onError the error callback to call on {@link Subscriber#onError(Throwable)} * * @return a new {@link Mono} */ public final Mono doOnError(Consumer onError) { Objects.requireNonNull(onError, "onError"); return doOnTerminalSignal(this, null, onError, null); } /** * Add behavior triggered when the {@link Mono} completes with an error matching the given exception type. *

* *

* The {@link Consumer} is executed first, then the onError signal is propagated * downstream. * * @param exceptionType the type of exceptions to handle * @param onError the error handler for relevant errors * @param type of the error to handle * * @return an observed {@link Mono} * */ public final Mono doOnError(Class exceptionType, final Consumer onError) { Objects.requireNonNull(exceptionType, "type"); Objects.requireNonNull(onError, "onError"); return doOnTerminalSignal(this, null, error -> { if (exceptionType.isInstance(error)) onError.accept(exceptionType.cast(error)); }, null); } /** * Add behavior triggered when the {@link Mono} completes with an error matching the given predicate. *

* *

* The {@link Consumer} is executed first, then the onError signal is propagated * downstream. * * @param predicate the matcher for exceptions to handle * @param onError the error handler for relevant error * * @return an observed {@link Mono} * */ public final Mono doOnError(Predicate predicate, final Consumer onError) { Objects.requireNonNull(predicate, "predicate"); Objects.requireNonNull(onError, "onError"); return doOnTerminalSignal(this, null, error -> { if (predicate.test(error)) onError.accept(error); }, null); } /** * Add behavior triggering a {@link LongConsumer} when the {@link Mono} receives any request. *

* Note that non fatal error raised in the callback will not be propagated and * will simply trigger {@link Operators#onOperatorError(Throwable, Context)}. * *

* *

* The {@link LongConsumer} is executed first, then the request signal is propagated * upstream to the parent. * * @param consumer the consumer to invoke on each request * * @return an observed {@link Mono} */ public final Mono doOnRequest(final LongConsumer consumer) { Objects.requireNonNull(consumer, "consumer"); return doOnSignal(this, null, null, consumer, null); } /** * Add behavior (side-effect) triggered when the {@link Mono} is being subscribed, * that is to say when a {@link Subscription} has been produced by the {@link Publisher} * and is being passed to the {@link Subscriber#onSubscribe(Subscription)}. *

* This method is not intended for capturing the subscription and calling its methods, * but for side effects like monitoring. For instance, the correct way to cancel a subscription is * to call {@link Disposable#dispose()} on the Disposable returned by {@link Mono#subscribe()}. *

* *

* The {@link Consumer} is executed first, then the {@link Subscription} is propagated * downstream to the next subscriber in the chain that is being established. * * @param onSubscribe the callback to call on {@link Subscriber#onSubscribe(Subscription)} * * @return a new {@link Mono} * @see #doFirst(Runnable) */ public final Mono doOnSubscribe(Consumer onSubscribe) { Objects.requireNonNull(onSubscribe, "onSubscribe"); return doOnSignal(this, onSubscribe, null, null, null); } /** * Add behavior triggered when the {@link Mono} terminates, either by completing with a value, * completing empty or failing with an error. Unlike in {@link Flux#doOnTerminate(Runnable)}, * the simple fact that a {@link Mono} emits {@link Subscriber#onNext(Object) onNext} implies * completion, so the handler is invoked BEFORE the element is propagated (same as with {@link #doOnSuccess(Consumer)}). * *

*

* The {@link Runnable} is executed first, then the onNext/onComplete/onError signal is propagated * downstream. * * @param onTerminate the callback to call {@link Subscriber#onNext}, {@link Subscriber#onComplete} without preceding {@link Subscriber#onNext} or {@link Subscriber#onError} * * @return a new {@link Mono} */ public final Mono doOnTerminate(Runnable onTerminate) { Objects.requireNonNull(onTerminate, "onTerminate"); return doOnTerminalSignal(this, ignoreValue -> onTerminate.run(), ignoreError -> onTerminate.run(), null); } /** * Map this {@link Mono} into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} * of timemillis and source data. The timemillis corresponds to the elapsed time between * the subscribe and the first next signal, as measured by the {@link Schedulers#parallel() parallel} scheduler. * *

* * * @return a new {@link Mono} that emits a tuple of time elapsed in milliseconds and matching data * @see #timed() */ public final Mono> elapsed() { return elapsed(Schedulers.parallel()); } /** * Map this {@link Mono} sequence into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} * of timemillis and source data. The timemillis corresponds to the elapsed time between the subscribe and the first * next signal, as measured by the provided {@link Scheduler}. * *

* * * @param scheduler a {@link Scheduler} instance to read time from * @return a new {@link Mono} that emits a tuple of time elapsed in milliseconds and matching data * @see #timed(Scheduler) */ public final Mono> elapsed(Scheduler scheduler) { Objects.requireNonNull(scheduler, "scheduler"); return onAssembly(new MonoElapsed<>(this, scheduler)); } /** * Recursively expand elements into a graph and emit all the resulting element, * in a depth-first traversal order. *

* That is: emit the value from this {@link Mono}, expand it and emit the first value * at this first level of recursion, and so on... When no more recursion is possible, * backtrack to the previous level and re-apply the strategy. *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *   - AB
	 *     - ab1
	 *   - a1
	 * 
* * Expands {@code Mono.just(A)} into *
	 *  A
	 *  AA
	 *  aa1
	 *  AB
	 *  ab1
	 *  a1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * @param capacityHint a capacity hint to prepare the inner queues to accommodate n * elements per level of recursion. * * @return this Mono expanded depth-first to a {@link Flux} */ public final Flux expandDeep(Function> expander, int capacityHint) { return Flux.onAssembly(new MonoExpand<>(this, expander, false, capacityHint)); } /** * Recursively expand elements into a graph and emit all the resulting element, * in a depth-first traversal order. *

* That is: emit the value from this {@link Mono}, expand it and emit the first value * at this first level of recursion, and so on... When no more recursion is possible, * backtrack to the previous level and re-apply the strategy. *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *   - AB
	 *     - ab1
	 *   - a1
	 * 
* * Expands {@code Mono.just(A)} into *
	 *  A
	 *  AA
	 *  aa1
	 *  AB
	 *  ab1
	 *  a1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * * @return this Mono expanded depth-first to a {@link Flux} */ public final Flux expandDeep(Function> expander) { return expandDeep(expander, Queues.SMALL_BUFFER_SIZE); } /** * Recursively expand elements into a graph and emit all the resulting element using * a breadth-first traversal strategy. *

* That is: emit the value from this {@link Mono} first, then expand it at a first level of * recursion and emit all of the resulting values, then expand all of these at a * second level and so on... *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *   - AB
	 *     - ab1
	 *   - a1
	 * 
* * Expands {@code Mono.just(A)} into *
	 *  A
	 *  AA
	 *  AB
	 *  a1
	 *  aa1
	 *  ab1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * @param capacityHint a capacity hint to prepare the inner queues to accommodate n * elements per level of recursion. * * @return this Mono expanded breadth-first to a {@link Flux} */ public final Flux expand(Function> expander, int capacityHint) { return Flux.onAssembly(new MonoExpand<>(this, expander, true, capacityHint)); } /** * Recursively expand elements into a graph and emit all the resulting element using * a breadth-first traversal strategy. *

* That is: emit the value from this {@link Mono} first, then expand it at a first level of * recursion and emit all of the resulting values, then expand all of these at a * second level and so on... *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *   - AB
	 *     - ab1
	 *   - a1
	 * 
* * Expands {@code Mono.just(A)} into *
	 *  A
	 *  AA
	 *  AB
	 *  a1
	 *  aa1
	 *  ab1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * * @return this Mono expanded breadth-first to a {@link Flux} */ public final Flux expand(Function> expander) { return expand(expander, Queues.SMALL_BUFFER_SIZE); } /** * If this {@link Mono} is valued, test the result and replay it if predicate returns true. * Otherwise complete without value. * *

* * *

Discard Support: This operator discards the element if it does not match the filter. It * also discards upon cancellation or error triggered by a data signal. * * @param tester the predicate to evaluate * * @return a filtered {@link Mono} */ public final Mono filter(final Predicate tester) { if (this instanceof Fuseable) { return onAssembly(new MonoFilterFuseable<>(this, tester)); } return onAssembly(new MonoFilter<>(this, tester)); } /** * If this {@link Mono} is valued, test the value asynchronously using a generated * {@code Publisher} test. The value from the Mono is replayed if the * first item emitted by the test is {@literal true}. It is dropped if the test is * either empty or its first emitted value is {@literal false}. *

* Note that only the first value of the test publisher is considered, and unless it * is a {@link Mono}, test will be cancelled after receiving that first value. * *

* * *

Discard Support: This operator discards the element if it does not match the filter. It * also discards upon cancellation or error triggered by a data signal. * * @param asyncPredicate the function generating a {@link Publisher} of {@link Boolean} * to filter the Mono with * * @return a filtered {@link Mono} */ public final Mono filterWhen(Function> asyncPredicate) { return onAssembly(new MonoFilterWhen<>(this, asyncPredicate)); } /** * Transform the item emitted by this {@link Mono} asynchronously, returning the * value emitted by another {@link Mono} (possibly changing the value type). * *

* * * @param transformer the function to dynamically bind a new {@link Mono} * @param the result type bound * * @return a new {@link Mono} with an asynchronously mapped value. */ public final Mono flatMap(Function> transformer) { return onAssembly(new MonoFlatMap<>(this, transformer)); } /** * Transform the item emitted by this {@link Mono} into a Publisher, then forward * its emissions into the returned {@link Flux}. * *

* * * @param mapper the * {@link Function} to produce a sequence of R from the eventual passed {@link Subscriber#onNext} * @param the merged sequence type * * @return a new {@link Flux} as the sequence is not guaranteed to be single at most */ public final Flux flatMapMany(Function> mapper) { return Flux.onAssembly(new MonoFlatMapMany<>(this, mapper)); } /** * Transform the signals emitted by this {@link Mono} into signal-specific Publishers, * then forward the applicable Publisher's emissions into the returned {@link Flux}. * *

* * * @param mapperOnNext the {@link Function} to call on next data and returning a sequence to merge * @param mapperOnError the {@link Function} to call on error signal and returning a sequence to merge * @param mapperOnComplete the {@link Function} to call on complete signal and returning a sequence to merge * @param the type of the produced inner sequence * * @return a new {@link Flux} as the sequence is not guaranteed to be single at most * * @see Flux#flatMap(Function, Function, Supplier) */ public final Flux flatMapMany(Function> mapperOnNext, Function> mapperOnError, Supplier> mapperOnComplete) { return flux().flatMap(mapperOnNext, mapperOnError, mapperOnComplete); } /** * Transform the item emitted by this {@link Mono} into {@link Iterable}, then forward * its elements into the returned {@link Flux}. * The {@link Iterable#iterator()} method will be called at least once and at most twice. * *

* *

* This operator inspects each {@link Iterable}'s {@link Spliterator} to assess if the iteration * can be guaranteed to be finite (see {@link Operators#onDiscardMultiple(Iterator, boolean, Context)}). * Since the default Spliterator wraps the Iterator we can have two {@link Iterable#iterator()} * calls per iterable. This second invocation is skipped on a {@link Collection } however, a type which is * assumed to be always finite. * *

Discard Support: Upon cancellation, this operator discards {@code T} elements it prefetched and, in * some cases, attempts to discard remainder of the currently processed {@link Iterable} (if it can * safely ensure the iterator is finite). Note that this means each {@link Iterable}'s {@link Iterable#iterator()} * method could be invoked twice. * * @param mapper the {@link Function} to transform input item into a sequence {@link Iterable} * @param the merged output sequence type * * @return a merged {@link Flux} * */ public final Flux flatMapIterable(Function> mapper) { return Flux.onAssembly(new MonoFlattenIterable<>(this, mapper, Integer .MAX_VALUE, Queues.one())); } /** * Convert this {@link Mono} to a {@link Flux} * * @return a {@link Flux} variant of this {@link Mono} */ public final Flux flux() { if (this instanceof Callable && !(this instanceof Fuseable.ScalarCallable)) { @SuppressWarnings("unchecked") Callable thiz = (Callable) this; return Flux.onAssembly(new FluxCallable<>(thiz)); } return Flux.from(this); } /** * Emit a single boolean true if this {@link Mono} has an element. * *

* * * @return a new {@link Mono} with true if a value is emitted and false * otherwise */ public final Mono hasElement() { return onAssembly(new MonoHasElement<>(this)); } /** * Handle the items emitted by this {@link Mono} by calling a biconsumer with the * output sink for each onNext. At most one {@link SynchronousSink#next(Object)} * call must be performed and/or 0 or 1 {@link SynchronousSink#error(Throwable)} or * {@link SynchronousSink#complete()}. *

* When the context-propagation library * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the * library to restore thread locals around the handler {@link BiConsumer}. Typically, this would be done in conjunction * with the use of {@link #contextCapture()} operator down the chain. * * @param handler the handling {@link BiConsumer} * @param the transformed type * * @return a transformed {@link Mono} */ public final Mono handle(BiConsumer> handler) { if (this instanceof Fuseable) { return onAssembly(new MonoHandleFuseable<>(this, handler)); } return onAssembly(new MonoHandle<>(this, handler)); } /** * Hides the identity of this {@link Mono} instance. * *

The main purpose of this operator is to prevent certain identity-based * optimizations from happening, mostly for diagnostic purposes. * * @return a new {@link Mono} preventing {@link Publisher} / {@link Subscription} based Reactor optimizations */ public final Mono hide() { return onAssembly(new MonoHide<>(this)); } /** * Ignores onNext signal (dropping it) and only propagates termination events. * *

* *

* *

Discard Support: This operator discards the source element. * * @return a new empty {@link Mono} representing the completion of this {@link Mono}. */ public final Mono ignoreElement() { return onAssembly(new MonoIgnoreElement<>(this)); } /** * Observe all Reactive Streams signals and trace them using {@link Logger} support. * Default will use {@link Level#INFO} and {@code java.util.logging}. * If SLF4J is available, it will be used instead. * *

* *

* The default log category will be "reactor.Mono", followed by a suffix generated from * the source operator, e.g. "reactor.Mono.Map". * * @return a new {@link Mono} that logs signals * * @see Flux#log() */ public final Mono log() { return log(null, Level.INFO); } /** * Observe all Reactive Streams signals and use {@link Logger} support to handle trace implementation. Default will * use {@link Level#INFO} and java.util.logging. If SLF4J is available, it will be used instead. * *

* * * @param category to be mapped into logger configuration (e.g. org.springframework * .reactor). If category ends with "." like "reactor.", a generated operator * suffix will complete, e.g. "reactor.Flux.Map". * * @return a new {@link Mono} */ public final Mono log(@Nullable String category) { return log(category, Level.INFO); } /** * Observe Reactive Streams signals matching the passed flags {@code options} and use * {@link Logger} support to handle trace implementation. Default will use the passed * {@link Level} and java.util.logging. If SLF4J is available, it will be used instead. * * Options allow fine grained filtering of the traced signal, for instance to only capture onNext and onError: *

	 *     mono.log("category", SignalType.ON_NEXT, SignalType.ON_ERROR)
	 * 
*

* * * @param category to be mapped into logger configuration (e.g. org.springframework * .reactor). If category ends with "." like "reactor.", a generated operator * suffix will complete, e.g. "reactor.Flux.Map". * @param level the {@link Level} to enforce for this tracing Mono (only FINEST, FINE, * INFO, WARNING and SEVERE are taken into account) * @param options a vararg {@link SignalType} option to filter log messages * * @return a new {@link Mono} * */ public final Mono log(@Nullable String category, Level level, SignalType... options) { return log(category, level, false, options); } /** * Observe Reactive Streams signals matching the passed filter {@code options} and * use {@link Logger} support to * handle trace * implementation. Default will * use the passed {@link Level} and java.util.logging. If SLF4J is available, it will be used instead. * * Options allow fine grained filtering of the traced signal, for instance to only capture onNext and onError: *

	 *     mono.log("category", Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
	 * 
*

* * * @param category to be mapped into logger configuration (e.g. org.springframework * .reactor). If category ends with "." like "reactor.", a generated operator * suffix will complete, e.g. "reactor.Mono.Map". * @param level the {@link Level} to enforce for this tracing Mono (only FINEST, FINE, * INFO, WARNING and SEVERE are taken into account) * @param showOperatorLine capture the current stack to display operator * class/line number. * @param options a vararg {@link SignalType} option to filter log messages * * @return a new unaltered {@link Mono} */ public final Mono log(@Nullable String category, Level level, boolean showOperatorLine, SignalType... options) { SignalLogger log = new SignalLogger<>(this, category, level, showOperatorLine, options); if (this instanceof Fuseable) { return onAssembly(new MonoLogFuseable<>(this, log)); } return onAssembly(new MonoLog<>(this, log)); } /** * Observe Reactive Streams signals matching the passed filter {@code options} and * trace them using a specific user-provided {@link Logger}, at {@link Level#INFO} level. *

* * * @param logger the {@link Logger} to use, instead of resolving one through a category. * * @return a new {@link Mono} that logs signals */ public final Mono log(Logger logger) { return log(logger, Level.INFO, false); } /** * Observe Reactive Streams signals matching the passed filter {@code options} and * trace them using a specific user-provided {@link Logger}, at the given {@link Level}. *

* Options allow fine grained filtering of the traced signal, for instance to only * capture onNext and onError: *

	 *     flux.log(myCustomLogger, Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
	 * 
*

* * * @param logger the {@link Logger} to use, instead of resolving one through a category. * @param level the {@link Level} to enforce for this tracing Flux (only FINEST, FINE, * INFO, WARNING and SEVERE are taken into account) * @param showOperatorLine capture the current stack to display operator class/line number. * @param options a vararg {@link SignalType} option to filter log messages * * @return a new {@link Mono} that logs signals */ public final Mono log(Logger logger, Level level, boolean showOperatorLine, SignalType... options) { SignalLogger log = new SignalLogger<>(this, "IGNORED", level, showOperatorLine, s -> logger, options); if (this instanceof Fuseable) { return onAssembly(new MonoLogFuseable<>(this, log)); } return onAssembly(new MonoLog<>(this, log)); } /** * Transform the item emitted by this {@link Mono} by applying a synchronous function to it. * *

* * * @param mapper the synchronous transforming {@link Function} * @param the transformed type * * @return a new {@link Mono} */ public final Mono map(Function mapper) { if (this instanceof Fuseable) { return onAssembly(new MonoMapFuseable<>(this, mapper)); } return onAssembly(new MonoMap<>(this, mapper)); } /** * Transform the item emitted by this {@link Mono} by applying a synchronous function to it, which is allowed * to produce a {@code null} value. In that case, the resulting Mono completes immediately. * This operator effectively behaves like {@link #map(Function)} followed by {@link #filter(Predicate)} * although {@code null} is not a supported value, so it can't be filtered out. * *

* * * @param mapper the synchronous transforming {@link Function} * @param the transformed type * * @return a new {@link Mono} */ public final Mono mapNotNull(Function mapper) { return this.handle((t, sink) -> { R r = mapper.apply(t); if (r != null) { sink.next(r); } }); } /** * Transform incoming onNext, onError and onComplete signals into {@link Signal} instances, * materializing these signals. * Since the error is materialized as a {@code Signal}, the propagation will be stopped and onComplete will be * emitted. Complete signal will first emit a {@code Signal.complete()} and then effectively complete the flux. * All these {@link Signal} have a {@link Context} associated to them. *

* * * @return a {@link Mono} of materialized {@link Signal} * @see #dematerialize() */ public final Mono> materialize() { return onAssembly(new MonoMaterialize<>(this)); } /** * Merge emissions of this {@link Mono} with the provided {@link Publisher}. * The element from the Mono may be interleaved with the elements of the Publisher. * *

* * * @param other the {@link Publisher} to merge with * * @return a new {@link Flux} as the sequence is not guaranteed to be at most 1 */ public final Flux mergeWith(Publisher other) { return Flux.merge(this, other); } /** * Activate metrics for this sequence, provided there is an instrumentation facade * on the classpath (otherwise this method is a pure no-op). *

* Metrics are gathered on {@link Subscriber} events, and it is recommended to also * {@link #name(String) name} (and optionally {@link #tag(String, String) tag}) the * sequence. *

* The name serves as a prefix in the reported metrics names. In case no name has been provided, the default name "reactor" will be applied. *

* The {@link MeterRegistry} used by reactor can be configured via * {@link reactor.util.Metrics.MicrometerConfiguration#useRegistry(MeterRegistry)} * prior to using this operator, the default being * {@link io.micrometer.core.instrument.Metrics#globalRegistry}. *

* * @return an instrumented {@link Mono} * * @see #name(String) * @see #tag(String, String) * @deprecated Prefer using the {@link #tap(SignalListenerFactory)} with the {@link SignalListenerFactory} provided by * the new reactor-core-micrometer module. To be removed in 3.6.0 at the earliest. */ @Deprecated public final Mono metrics() { if (!Metrics.isInstrumentationAvailable()) { return this; } if (this instanceof Fuseable) { return onAssembly(new MonoMetricsFuseable<>(this)); } return onAssembly(new MonoMetrics<>(this)); } /** * Give a name to this sequence, which can be retrieved using {@link Scannable#name()} * as long as this is the first reachable {@link Scannable#parents()}. *

* The name is typically visible at assembly time by the {@link #tap(SignalListenerFactory)} operator, * which could for example be configured with a metrics listener using the name as a prefix for meters' id. * * @param name a name for the sequence * * @return the same sequence, but bearing a name * * @see #metrics() * @see #tag(String, String) */ public final Mono name(String name) { return MonoName.createOrAppend(this, name); } /** * Emit the first available signal from this mono or the other mono. * *

* * * @param other the racing other {@link Mono} to compete with for the signal * * @return a new {@link Mono} * @see #firstWithSignal */ public final Mono or(Mono other) { if (this instanceof MonoFirstWithSignal) { MonoFirstWithSignal a = (MonoFirstWithSignal) this; Mono result = a.orAdditionalSource(other); if (result != null) { return result; } } return firstWithSignal(this, other); } /** * Evaluate the emitted value against the given {@link Class} type. If the * value matches the type, it is passed into the new {@link Mono}. Otherwise the * value is ignored. * *

* * * @param clazz the {@link Class} type to test values against * * @return a new {@link Mono} filtered on the requested type */ public final Mono ofType(final Class clazz) { Objects.requireNonNull(clazz, "clazz"); return filter(o -> clazz.isAssignableFrom(o.getClass())).cast(clazz); } /** * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} * with an {@link Subscriber#onComplete() onComplete signal}. All other signals are propagated as-is. * *

* * * @return a new {@link Mono} falling back on completion when an onError occurs * @see #onErrorReturn(Object) */ public final Mono onErrorComplete() { return onAssembly(new MonoOnErrorReturn<>(this, null, null)); } /** * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} * with an {@link Subscriber#onComplete() onComplete signal} if the error matches the given * {@link Class}. All other signals, including non-matching onError, are propagated as-is. * *

* * * @return a new {@link Mono} falling back on completion when a matching error occurs * @see #onErrorReturn(Class, Object) */ public final Mono onErrorComplete(Class type) { Objects.requireNonNull(type, "type must not be null"); return onErrorComplete(type::isInstance); } /** * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} * with an {@link Subscriber#onComplete() onComplete signal} if the error matches the given * {@link Predicate}. All other signals, including non-matching onError, are propagated as-is. * *

* * * @return a new {@link Mono} falling back on completion when a matching error occurs * @see #onErrorReturn(Predicate, Object) */ public final Mono onErrorComplete(Predicate predicate) { Objects.requireNonNull(predicate, "predicate must not be null"); return onAssembly(new MonoOnErrorReturn<>(this, predicate, null)); } /** * Let compatible operators upstream recover from errors by dropping the * incriminating element from the sequence and continuing with subsequent elements. * The recovered error and associated value are notified via the provided {@link BiConsumer}. * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream * in place of the original error, which is added as a suppressed exception to the new one. *

* This operator is offered on {@link Mono} mainly as a way to propagate the configuration to * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure * there will be no further value to continue with. * {@link #onErrorResume(Function)} is a more classical fit. *

* Note that onErrorContinue() is a specialist operator that can make the behaviour of your * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific * operator support to work, and the scope can easily propagate upstream into library code * that didn't anticipate it (resulting in unintended behaviour.) *

* In most cases, you should instead handle the error inside the specific function which may cause * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: *

*

	 * .flatMap(id -> repository.retrieveById(id)
	 *                          .doOnError(System.err::println)
	 *                          .onErrorResume(e -> Mono.empty()))
	 * 
*

* This has the advantage of being much clearer, has no ambiguity with regards to operator support, * and cannot leak upstream. * * @param errorConsumer a {@link BiConsumer} fed with errors matching the {@link Class} * and the value that triggered the error. * @return a {@link Mono} that attempts to continue processing on errors. */ public final Mono onErrorContinue(BiConsumer errorConsumer) { BiConsumer genericConsumer = errorConsumer; return contextWrite(Context.of( OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, OnNextFailureStrategy.resume(genericConsumer) )); } /** * Let compatible operators upstream recover from errors by dropping the * incriminating element from the sequence and continuing with subsequent elements. * Only errors matching the specified {@code type} are recovered from. * The recovered error and associated value are notified via the provided {@link BiConsumer}. * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream * in place of the original error, which is added as a suppressed exception to the new one. *

* This operator is offered on {@link Mono} mainly as a way to propagate the configuration to * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure * there will be no further value to continue with. * {@link #onErrorResume(Function)} is a more classical fit. *

* Note that onErrorContinue() is a specialist operator that can make the behaviour of your * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific * operator support to work, and the scope can easily propagate upstream into library code * that didn't anticipate it (resulting in unintended behaviour.) *

* In most cases, you should instead handle the error inside the specific function which may cause * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: *

*

	 * .flatMap(id -> repository.retrieveById(id)
	 *                          .doOnError(MyException.class, System.err::println)
	 *                          .onErrorResume(MyException.class, e -> Mono.empty()))
	 * 
*

* This has the advantage of being much clearer, has no ambiguity with regards to operator support, * and cannot leak upstream. * * @param type the {@link Class} of {@link Exception} that are resumed from. * @param errorConsumer a {@link BiConsumer} fed with errors matching the {@link Class} * and the value that triggered the error. * @return a {@link Mono} that attempts to continue processing on some errors. */ public final Mono onErrorContinue(Class type, BiConsumer errorConsumer) { return onErrorContinue(type::isInstance, errorConsumer); } /** * Let compatible operators upstream recover from errors by dropping the * incriminating element from the sequence and continuing with subsequent elements. * Only errors matching the {@link Predicate} are recovered from (note that this * predicate can be applied several times and thus must be idempotent). * The recovered error and associated value are notified via the provided {@link BiConsumer}. * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream * in place of the original error, which is added as a suppressed exception to the new one. *

* This operator is offered on {@link Mono} mainly as a way to propagate the configuration to * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure * there will be no further value to continue with. * {@link #onErrorResume(Function)} is a more classical fit. *

* Note that onErrorContinue() is a specialist operator that can make the behaviour of your * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific * operator support to work, and the scope can easily propagate upstream into library code * that didn't anticipate it (resulting in unintended behaviour.) *

* In most cases, you should instead handle the error inside the specific function which may cause * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: *

*

	 * .flatMap(id -> repository.retrieveById(id)
	 *                          .doOnError(errorPredicate, System.err::println)
	 *                          .onErrorResume(errorPredicate, e -> Mono.empty()))
	 * 
*

* This has the advantage of being much clearer, has no ambiguity with regards to operator support, * and cannot leak upstream. * * @param errorPredicate a {@link Predicate} used to filter which errors should be resumed from. * This MUST be idempotent, as it can be used several times. * @param errorConsumer a {@link BiConsumer} fed with errors matching the predicate and the value * that triggered the error. * @return a {@link Mono} that attempts to continue processing on some errors. */ public final Mono onErrorContinue(Predicate errorPredicate, BiConsumer errorConsumer) { //this cast is ok as only T values will be propagated in this sequence @SuppressWarnings("unchecked") Predicate genericPredicate = (Predicate) errorPredicate; BiConsumer genericErrorConsumer = errorConsumer; return contextWrite(Context.of( OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, OnNextFailureStrategy.resumeIf(genericPredicate, genericErrorConsumer) )); } /** * If an {@link #onErrorContinue(BiConsumer)} variant has been used downstream, reverts * to the default 'STOP' mode where errors are terminal events upstream. It can be * used for easier scoping of the on next failure strategy or to override the * inherited strategy in a sub-stream (for example in a flatMap). It has no effect if * {@link #onErrorContinue(BiConsumer)} has not been used downstream. * * @return a {@link Mono} that terminates on errors, even if {@link #onErrorContinue(BiConsumer)} * was used downstream */ public final Mono onErrorStop() { return contextWrite(Context.of( OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, OnNextFailureStrategy.stop())); } /** * Transform an error emitted by this {@link Mono} by synchronously applying a function * to it if the error matches the given predicate. Otherwise let the error pass through. *

* * * @param predicate the error predicate * @param mapper the error transforming {@link Function} * * @return a {@link Mono} that transforms some source errors to other errors */ public final Mono onErrorMap(Predicate predicate, Function mapper) { return onErrorResume(predicate, e -> Mono.error(mapper.apply(e))); } /** * Transform any error emitted by this {@link Mono} by synchronously applying a function to it. *

* * * @param mapper the error transforming {@link Function} * * @return a {@link Mono} that transforms source errors to other errors */ public final Mono onErrorMap(Function mapper) { return onErrorResume(e -> Mono.error(mapper.apply(e))); } /** * Transform an error emitted by this {@link Mono} by synchronously applying a function * to it if the error matches the given type. Otherwise let the error pass through. *

* * * @param type the class of the exception type to react to * @param mapper the error transforming {@link Function} * @param the error type * * @return a {@link Mono} that transforms some source errors to other errors */ public final Mono onErrorMap(Class type, Function mapper) { @SuppressWarnings("unchecked") Function handler = (Function)mapper; return onErrorMap(type::isInstance, handler); } /** * Subscribe to a fallback publisher when any error occurs, using a function to * choose the fallback depending on the error. * *

* * * @param fallback the function to choose the fallback to an alternative {@link Mono} * * @return a {@link Mono} falling back upon source onError * * @see Flux#onErrorResume */ public final Mono onErrorResume(Function> fallback) { return onAssembly(new MonoOnErrorResume<>(this, fallback)); } /** * Subscribe to a fallback publisher when an error matching the given type * occurs, using a function to choose the fallback depending on the error. *

* * * @param type the error type to match * @param fallback the function to choose the fallback to an alternative {@link Mono} * @param the error type * * @return a {@link Mono} falling back upon source onError * @see Flux#onErrorResume */ public final Mono onErrorResume(Class type, Function> fallback) { Objects.requireNonNull(type, "type"); @SuppressWarnings("unchecked") Function> handler = (Function>)fallback; return onErrorResume(type::isInstance, handler); } /** * Subscribe to a fallback publisher when an error matching a given predicate * occurs. *

* * * @param predicate the error predicate to match * @param fallback the function to choose the fallback to an alternative {@link Mono} * @return a {@link Mono} falling back upon source onError * @see Flux#onErrorResume */ public final Mono onErrorResume(Predicate predicate, Function> fallback) { Objects.requireNonNull(predicate, "predicate"); return onErrorResume(e -> predicate.test(e) ? fallback.apply(e) : error(e)); } /** * Simply emit a captured fallback value when any error is observed on this {@link Mono}. * *

* * * @param fallbackValue the value to emit if an error occurs * * @return a new falling back {@link Mono} * @see #onErrorComplete() */ public final Mono onErrorReturn(final T fallbackValue) { Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); return onAssembly(new MonoOnErrorReturn<>(this, null, fallbackValue)); } /** * Simply emit a captured fallback value when an error of the specified type is * observed on this {@link Mono}. *

* * * @param type the error type to match * @param fallbackValue the value to emit if an error occurs that matches the type * @param the error type * * @return a new falling back {@link Mono} * @see #onErrorComplete(Class) */ public final Mono onErrorReturn(Class type, T fallbackValue) { Objects.requireNonNull(type, "type must not be null"); Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); return onErrorReturn(type::isInstance, fallbackValue); } /** * Simply emit a captured fallback value when an error matching the given predicate is * observed on this {@link Mono}. *

* * * @param predicate the error predicate to match * @param fallbackValue the value to emit if an error occurs that matches the predicate * * @return a new {@link Mono} * @see #onErrorComplete(Predicate) */ public final Mono onErrorReturn(Predicate predicate, T fallbackValue) { Objects.requireNonNull(predicate, "predicate must not be null"); Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); return onAssembly(new MonoOnErrorReturn<>(this, predicate, fallbackValue)); } /** * Detaches both the child {@link Subscriber} and the {@link Subscription} on * termination or cancellation. *

This should help with odd retention scenarios when running * with non-reactor {@link Subscriber}. * * @return a detachable {@link Mono} */ public final Mono onTerminateDetach() { return new MonoDetach<>(this); } /** * Share a {@link Mono} for the duration of a function that may transform it and * consume it as many times as necessary without causing multiple subscriptions * to the upstream. * * @param transform the transformation function * @param the output value type * * @return a new {@link Mono} */ public final Mono publish(Function, ? extends Mono> transform) { return onAssembly(new MonoPublishMulticast<>(this, transform)); } /** * Run onNext, onComplete and onError on a supplied {@link Scheduler} * {@link Worker Worker}. *

* This operator influences the threading context where the rest of the operators in * the chain below it will execute, up to a new occurrence of {@code publishOn}. *

* *

* Typically used for fast publisher, slow consumer(s) scenarios. * *

	 * {@code mono.publishOn(Schedulers.single()).subscribe() }
	 * 
* * @param scheduler a {@link Scheduler} providing the {@link Worker} where to publish * * @return an asynchronously producing {@link Mono} */ public final Mono publishOn(Scheduler scheduler) { if(this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { try { T value = block(); return onAssembly(new MonoSubscribeOnValue<>(value, scheduler)); } catch (Throwable t) { //leave MonoSubscribeOnCallable defer error } } @SuppressWarnings("unchecked") Callable c = (Callable)this; return onAssembly(new MonoSubscribeOnCallable<>(c, scheduler)); } return onAssembly(new MonoPublishOn<>(this, scheduler)); } /** * Repeatedly and indefinitely subscribe to the source upon completion of the * previous subscription. * *

* * * @return an indefinitely repeated {@link Flux} on onComplete */ public final Flux repeat() { return repeat(Flux.ALWAYS_BOOLEAN_SUPPLIER); } /** * Repeatedly subscribe to the source if the predicate returns true after completion of the previous subscription. * *

* * * @param predicate the boolean to evaluate on onComplete. * * @return a {@link Flux} that repeats on onComplete while the predicate matches * */ public final Flux repeat(BooleanSupplier predicate) { return Flux.onAssembly(new MonoRepeatPredicate<>(this, predicate)); } /** * Repeatedly subscribe to the source {@literal numRepeat} times. This results in * {@code numRepeat + 1} total subscriptions to the original source. As a consequence, * using 0 plays the original sequence once. * *

* * * @param numRepeat the number of times to re-subscribe on onComplete (positive, or 0 for original sequence only) * @return a {@link Flux} that repeats on onComplete, up to the specified number of repetitions */ public final Flux repeat(long numRepeat) { if (numRepeat == 0) { return this.flux(); } return Flux.onAssembly(new MonoRepeat<>(this, numRepeat)); } /** * Repeatedly subscribe to the source if the predicate returns true after completion of the previous * subscription. A specified maximum of repeat will limit the number of re-subscribe. * *

* * * @param numRepeat the number of times to re-subscribe on complete (positive, or 0 for original sequence only) * @param predicate the boolean to evaluate on onComplete * * @return a {@link Flux} that repeats on onComplete while the predicate matches, * up to the specified number of repetitions */ public final Flux repeat(long numRepeat, BooleanSupplier predicate) { if (numRepeat < 0L) { throw new IllegalArgumentException("numRepeat >= 0 required"); } if (numRepeat == 0) { return this.flux(); } return Flux.defer(() -> repeat(Flux.countingBooleanSupplier(predicate, numRepeat))); } /** * Repeatedly subscribe to this {@link Mono} when a companion sequence emits elements in * response to the flux completion signal. Any terminal signal from the companion * sequence will terminate the resulting {@link Flux} with the same signal immediately. *

If the companion sequence signals when this {@link Mono} is active, the repeat * attempt is suppressed. * *

* *

* Note that if the companion {@link Publisher} created by the {@code repeatFactory} * emits {@link Context} as trigger objects, the content of these Context will be added * to the operator's own {@link Context}. * * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} * companion, given a {@link Flux} that signals each onComplete as a {@link Long} * representing the number of source elements emitted in the latest attempt (0 or 1). * * @return a {@link Flux} that repeats on onComplete when the companion {@link Publisher} produces an * onNext signal */ public final Flux repeatWhen(Function, ? extends Publisher> repeatFactory) { return Flux.onAssembly(new MonoRepeatWhen<>(this, repeatFactory)); } /** * Repeatedly subscribe to this {@link Mono} as long as the current subscription to this * {@link Mono} completes empty and the companion {@link Publisher} produces an onNext signal. *

* Any terminal signal will terminate the resulting {@link Mono} with the same signal immediately. * *

* * * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} * companion, given a {@link Flux} that signals each onComplete as a 0-based incrementing {@link Long}. * * @return a {@link Mono} that resubscribes to this {@link Mono} if the previous subscription was empty, * as long as the companion {@link Publisher} produces an onNext signal * */ public final Mono repeatWhenEmpty(Function, ? extends Publisher> repeatFactory) { return repeatWhenEmpty(Integer.MAX_VALUE, repeatFactory); } /** * Repeatedly subscribe to this {@link Mono} as long as the current subscription to this * {@link Mono} completes empty and the companion {@link Publisher} produces an onNext signal. *

* Any terminal signal will terminate the resulting {@link Mono} with the same signal immediately. *

* Emits an {@link IllegalStateException} if {@code maxRepeat} is exceeded (provided * it is different from {@code Integer.MAX_VALUE}). * *

* * * @param maxRepeat the maximum number of repeats (infinite if {@code Integer.MAX_VALUE}) * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} * companion, given a {@link Flux} that signals each onComplete as a 0-based incrementing {@link Long}. * * @return a {@link Mono} that resubscribes to this {@link Mono} if the previous subscription was empty, * as long as the companion {@link Publisher} produces an onNext signal and the maximum number of repeats isn't exceeded. */ public final Mono repeatWhenEmpty(int maxRepeat, Function, ? extends Publisher> repeatFactory) { return Mono.defer(() -> this.repeatWhen(o -> { if (maxRepeat == Integer.MAX_VALUE) { return repeatFactory.apply(o.index().map(Tuple2::getT1)); } else { return repeatFactory.apply(o .index() .map(Tuple2::getT1) .take(maxRepeat, false) .concatWith(Flux.error(() -> new IllegalStateException("Exceeded maximum number of repeats")))); } }).next()); } /** * Re-subscribes to this {@link Mono} sequence if it signals any error, indefinitely. *

* * * @return a {@link Mono} that retries on onError */ public final Mono retry() { return retry(Long.MAX_VALUE); } /** * Re-subscribes to this {@link Mono} sequence if it signals any error, for a fixed * number of times. *

* Note that passing {@literal Long.MAX_VALUE} is treated as infinite retry. *

* * * @param numRetries the number of times to tolerate an error * * @return a {@link Mono} that retries on onError up to the specified number of retry attempts. */ public final Mono retry(long numRetries) { return onAssembly(new MonoRetry<>(this, numRetries)); } /** * Retries this {@link Mono} in response to signals emitted by a companion {@link Publisher}. * The companion is generated by the provided {@link Retry} instance, see {@link Retry#max(long)}, {@link Retry#maxInARow(long)} * and {@link Retry#backoff(long, Duration)} for readily available strategy builders. *

* The operator generates a base for the companion, a {@link Flux} of {@link reactor.util.retry.Retry.RetrySignal} * which each give metadata about each retryable failure whenever this {@link Mono} signals an error. The final companion * should be derived from that base companion and emit data in response to incoming onNext (although it can emit less * elements, or delay the emissions). *

* Terminal signals in the companion terminate the sequence with the same signal, so emitting an {@link Subscriber#onError(Throwable)} * will fail the resulting {@link Mono} with that same error. *

* *

* Note that the {@link reactor.util.retry.Retry.RetrySignal} state can be transient and change between each source * {@link org.reactivestreams.Subscriber#onError(Throwable) onError} or * {@link org.reactivestreams.Subscriber#onNext(Object) onNext}. If processed with a delay, * this could lead to the represented state being out of sync with the state at which the retry * was evaluated. Map it to {@link reactor.util.retry.Retry.RetrySignal#copy()} right away to mediate this. *

* Note that if the companion {@link Publisher} created by the {@code whenFactory} * emits {@link Context} as trigger objects, these {@link Context} will be merged with * the previous Context: *

*
	 * {@code
	 * Retry customStrategy = Retry.from(companion -> companion.handle((retrySignal, sink) -> {
	 * 	    Context ctx = sink.currentContext();
	 * 	    int rl = ctx.getOrDefault("retriesLeft", 0);
	 * 	    if (rl > 0) {
	 *		    sink.next(Context.of(
	 *		        "retriesLeft", rl - 1,
	 *		        "lastError", retrySignal.failure()
	 *		    ));
	 * 	    } else {
	 * 	        sink.error(Exceptions.retryExhausted("retries exhausted", retrySignal.failure()));
	 * 	    }
	 * }));
	 * Mono retried = originalMono.retryWhen(customStrategy);
	 * }
*
* * @param retrySpec the {@link Retry} strategy that will generate the companion {@link Publisher}, * given a {@link Flux} that signals each onError as a {@link reactor.util.retry.Retry.RetrySignal}. * * @return a {@link Mono} that retries on onError when a companion {@link Publisher} produces an onNext signal * @see Retry#max(long) * @see Retry#maxInARow(long) * @see Retry#backoff(long, Duration) */ public final Mono retryWhen(Retry retrySpec) { return onAssembly(new MonoRetryWhen<>(this, retrySpec)); } /** * Prepare a {@link Mono} which shares this {@link Mono} result similar to {@link Flux#shareNext()}. * This will effectively turn this {@link Mono} into a hot task when the first * {@link Subscriber} subscribes using {@link #subscribe()} API. Further {@link Subscriber} will share the same {@link Subscription} * and therefore the same result. * It's worth noting this is an un-cancellable {@link Subscription}. *

* * * @return a new {@link Mono} */ public final Mono share() { if (this instanceof Fuseable.ScalarCallable) { return this; } if (this instanceof NextProcessor && ((NextProcessor) this).isRefCounted) { //TODO should we check whether the NextProcessor has a source or not? return this; } return new NextProcessor<>(this, true); } /** * Expect exactly one item from this {@link Mono} source or signal * {@link java.util.NoSuchElementException} for an empty source. *

* *

* Note Mono doesn't need {@link Flux#single(Object)}, since it is equivalent to * {@link #defaultIfEmpty(Object)} in a {@link Mono}. * * @return a {@link Mono} with the single item or an error signal */ public final Mono single() { if (this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { @SuppressWarnings("unchecked") Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; T v; try { v = scalarCallable.call(); } catch (Exception e) { return Mono.error(Exceptions.unwrap(e)); } if (v == null) { return Mono.error(new NoSuchElementException("Source was a (constant) empty")); } return Mono.just(v); } @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return Mono.onAssembly(new MonoSingleCallable<>(thiz)); } return Mono.onAssembly(new MonoSingleMono<>(this)); } /** * Wrap the item produced by this {@link Mono} source into an Optional * or emit an empty Optional for an empty source. *

* *

* * @return a {@link Mono} with an Optional containing the item, an empty optional or an error signal */ public final Mono> singleOptional() { if (this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { @SuppressWarnings("unchecked") Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; T v; try { v = scalarCallable.call(); } catch (Exception e) { return Mono.error(Exceptions.unwrap(e)); } return Mono.just(Optional.ofNullable(v)); } @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return Mono.onAssembly(new MonoSingleOptionalCallable<>(thiz)); } return Mono.onAssembly(new MonoSingleOptional<>(this)); } /** * Subscribe to this {@link Mono} and request unbounded demand. *

* This version doesn't specify any consumption behavior for the events from the * chain, especially no error handling, so other variants should usually be preferred. * *

* * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe() { if(this instanceof NextProcessor){ NextProcessor s = (NextProcessor)this; // Mono#share() should return a new lambda subscriber during subscribe. // This can now be precisely detected with source != null in combination to the isRefCounted boolean being true. // `Sinks.one().subscribe()` case is now split into a separate implementation. // Otherwise, this is a (legacy) #toProcessor() usage, and we return the processor itself below (and don't forget to connect() it): if (s.source != null && !s.isRefCounted) { s.subscribe(new LambdaMonoSubscriber<>(null, null, null, null, null)); s.connect(); return s; } } return subscribeWith(new LambdaMonoSubscriber<>(null, null, null, null, null)); } /** * Subscribe a {@link Consumer} to this {@link Mono} that will consume all the * sequence. It will request an unbounded demand ({@code Long.MAX_VALUE}). *

* For a passive version that observe and forward incoming data see {@link #doOnNext(java.util.function.Consumer)}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each value (onNext signal) * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe(Consumer consumer) { Objects.requireNonNull(consumer, "consumer"); return subscribe(consumer, null, null); } /** * Subscribe to this {@link Mono} with a {@link Consumer} that will consume all the * elements in the sequence, as well as a {@link Consumer} that will handle errors. * The subscription will request an unbounded demand ({@code Long.MAX_VALUE}). *

* For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and * {@link #doOnError(java.util.function.Consumer)}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each next signal * @param errorConsumer the consumer to invoke on error signal * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe(@Nullable Consumer consumer, Consumer errorConsumer) { Objects.requireNonNull(errorConsumer, "errorConsumer"); return subscribe(consumer, errorConsumer, null); } /** * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the * elements in the sequence, handle errors and react to completion. The subscription * will request unbounded demand ({@code Long.MAX_VALUE}). *

* For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and * {@link #doOnError(java.util.function.Consumer)}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each value * @param errorConsumer the consumer to invoke on error signal * @param completeConsumer the consumer to invoke on complete signal * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe( @Nullable Consumer consumer, @Nullable Consumer errorConsumer, @Nullable Runnable completeConsumer) { return subscribe(consumer, errorConsumer, completeConsumer, (Context) null); } /** * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the * elements in the sequence, handle errors, react to completion, and request upon subscription. * It will let the provided {@link Subscription subscriptionConsumer} * request the adequate amount of data, or request unbounded demand * {@code Long.MAX_VALUE} if no such consumer is provided. *

* For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and * {@link #doOnError(java.util.function.Consumer)}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each value * @param errorConsumer the consumer to invoke on error signal * @param completeConsumer the consumer to invoke on complete signal * @param subscriptionConsumer the consumer to invoke on subscribe signal, to be used * for the initial {@link Subscription#request(long) request}, or null for max request * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ //TODO maybe deprecate in 3.4, provided there is at least an alternative for tests public final Disposable subscribe( @Nullable Consumer consumer, @Nullable Consumer errorConsumer, @Nullable Runnable completeConsumer, @Nullable Consumer subscriptionConsumer) { return subscribeWith(new LambdaMonoSubscriber<>(consumer, errorConsumer, completeConsumer, subscriptionConsumer, null)); } /** * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the * elements in the sequence, handle errors and react to completion. Additionally, a {@link Context} * is tied to the subscription. At subscription, an unbounded request is implicitly made. *

* For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and * {@link #doOnError(java.util.function.Consumer)}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each value * @param errorConsumer the consumer to invoke on error signal * @param completeConsumer the consumer to invoke on complete signal * @param initialContext the {@link Context} for the subscription * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe( @Nullable Consumer consumer, @Nullable Consumer errorConsumer, @Nullable Runnable completeConsumer, @Nullable Context initialContext) { return subscribeWith(new LambdaMonoSubscriber<>(consumer, errorConsumer, completeConsumer, null, initialContext)); } @Override @SuppressWarnings("unchecked") public final void subscribe(Subscriber actual) { CorePublisher publisher = Operators.onLastAssembly(this); CoreSubscriber subscriber = Operators.toCoreSubscriber(actual); if (subscriber instanceof Fuseable.QueueSubscription && this != publisher && this instanceof Fuseable && !(publisher instanceof Fuseable)) { subscriber = new FluxHide.SuppressFuseableSubscriber<>(subscriber); } try { if (publisher instanceof OptimizableOperator) { OptimizableOperator operator = (OptimizableOperator) publisher; while (true) { subscriber = operator.subscribeOrReturn(subscriber); if (subscriber == null) { // null means "I will subscribe myself", returning... return; } OptimizableOperator newSource = operator.nextOptimizableSource(); if (newSource == null) { publisher = operator.source(); break; } operator = newSource; } } subscriber = Operators.restoreContextOnSubscriberIfPublisherNonInternal(publisher, subscriber); publisher.subscribe(subscriber); } catch (Throwable e) { Operators.reportThrowInSubscribe(subscriber, e); return; } } /** * An internal {@link Publisher#subscribe(Subscriber)} that will bypass * {@link Hooks#onLastOperator(Function)} pointcut. *

* In addition to behave as expected by {@link Publisher#subscribe(Subscriber)} * in a controlled manner, it supports direct subscribe-time {@link Context} passing. * * @param actual the {@link Subscriber} interested into the published sequence * @see Publisher#subscribe(Subscriber) */ public abstract void subscribe(CoreSubscriber actual); /** * Run subscribe, onSubscribe and request on a specified {@link Scheduler}'s {@link Worker}. * As such, placing this operator anywhere in the chain will also impact the execution * context of onNext/onError/onComplete signals from the beginning of the chain up to * the next occurrence of a {@link #publishOn(Scheduler) publishOn}. *

* * *

	 * {@code mono.subscribeOn(Schedulers.parallel()).subscribe() }
	 * 
* * @param scheduler a {@link Scheduler} providing the {@link Worker} where to subscribe * * @return a {@link Mono} requesting asynchronously * @see #publishOn(Scheduler) */ public final Mono subscribeOn(Scheduler scheduler) { if(this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { try { T value = block(); return onAssembly(new MonoSubscribeOnValue<>(value, scheduler)); } catch (Throwable t) { //leave MonoSubscribeOnCallable defer error } } @SuppressWarnings("unchecked") Callable c = (Callable)this; return onAssembly(new MonoSubscribeOnCallable<>(c, scheduler)); } return onAssembly(new MonoSubscribeOn<>(this, scheduler)); } /** * Subscribe the given {@link Subscriber} to this {@link Mono} and return said * {@link Subscriber}, allowing subclasses with a richer API to be used fluently. * * @param subscriber the {@link Subscriber} to subscribe with * @param the reified type of the {@link Subscriber} for chaining * * @return the passed {@link Subscriber} after subscribing it to this {@link Mono} */ public final > E subscribeWith(E subscriber) { subscribe(subscriber); return subscriber; } /** * Fallback to an alternative {@link Mono} if this mono is completed without data * *

* * * @param alternate the alternate mono if this mono is empty * * @return a {@link Mono} falling back upon source completing without elements * @see Flux#switchIfEmpty */ public final Mono switchIfEmpty(Mono alternate) { return onAssembly(new MonoSwitchIfEmpty<>(this, alternate)); } /** * Tag this mono with a key/value pair. These can be retrieved as a {@link Set} of * all tags throughout the publisher chain by using {@link Scannable#tags()} (as * traversed by {@link Scannable#parents()}). *

* The name is typically visible at assembly time by the {@link #tap(SignalListenerFactory)} operator, * which could for example be configured with a metrics listener applying the tag(s) to its meters. * * @param key a tag key * @param value a tag value * * @return the same sequence, but bearing tags * * @see #name(String) * @see #metrics() */ public final Mono tag(String key, String value) { return MonoName.createOrAppend(this, key, value); } /** * Give this Mono a chance to resolve within a specified time frame but complete if it * doesn't. This works a bit like {@link #timeout(Duration)} except that the resulting * {@link Mono} completes rather than errors when the timer expires. *

* *

* The timeframe is evaluated using the {@link Schedulers#parallel() parallel Scheduler}. * * @param duration the maximum duration to wait for the source Mono to resolve. * @return a new {@link Mono} that will propagate the signals from the source unless * no signal is received for {@code duration}, in which case it completes. */ public final Mono take(Duration duration) { return take(duration, Schedulers.parallel()); } /** * Give this Mono a chance to resolve within a specified time frame but complete if it * doesn't. This works a bit like {@link #timeout(Duration)} except that the resulting * {@link Mono} completes rather than errors when the timer expires. *

* *

* The timeframe is evaluated using the provided {@link Scheduler}. * * @param duration the maximum duration to wait for the source Mono to resolve. * @param timer the {@link Scheduler} on which to measure the duration. * * @return a new {@link Mono} that will propagate the signals from the source unless * no signal is received for {@code duration}, in which case it completes. */ public final Mono take(Duration duration, Scheduler timer) { return takeUntilOther(Mono.delay(duration, timer)); } /** * Give this Mono a chance to resolve before a companion {@link Publisher} emits. If * the companion emits before any signal from the source, the resulting Mono will * complete. Otherwise, it will relay signals from the source. *

* * * @param other a companion {@link Publisher} that shortcircuits the source with an * onComplete signal if it emits before the source emits. * * @return a new {@link Mono} that will propagate the signals from the source unless * a signal is first received from the companion {@link Publisher}, in which case it * completes. */ public final Mono takeUntilOther(Publisher other) { return onAssembly(new MonoTakeUntilOther<>(this, other)); } /** * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} * {@link SignalListener}. *

* Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} * the exception. *

* This simplified variant assumes the state is purely initialized within the {@link Supplier}, * as it is called for each incoming {@link Subscriber} without additional context. *

* When the context-propagation library * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the library * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done * in conjunction with the use of {@link #contextCapture()} operator down the chain. * * @param simpleListenerGenerator the {@link Supplier} to create a new {@link SignalListener} on each subscription * @return a new {@link Mono} with side effects defined by generated {@link SignalListener} * @see #tap(Function) * @see #tap(SignalListenerFactory) */ public final Mono tap(Supplier> simpleListenerGenerator) { return tap(new SignalListenerFactory() { @Override public Void initializePublisherState(Publisher ignored) { return null; } @Override public SignalListener createListener(Publisher ignored1, ContextView ignored2, Void ignored3) { return simpleListenerGenerator.get(); } }); } /** * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} * {@link SignalListener}. *

* Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} * the exception. *

* This simplified variant allows the {@link SignalListener} to be constructed for each subscription * with access to the incoming {@link Subscriber}'s {@link ContextView}. *

* When the context-propagation library * is available at runtime and the {@link ContextView} is not empty, this operator implicitly uses the library * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done * in conjunction with the use of {@link #contextCapture()} operator down the chain. * * @param listenerGenerator the {@link Function} to create a new {@link SignalListener} on each subscription * @return a new {@link Mono} with side effects defined by generated {@link SignalListener} * @see #tap(Supplier) * @see #tap(SignalListenerFactory) */ public final Mono tap(Function> listenerGenerator) { return tap(new SignalListenerFactory() { @Override public Void initializePublisherState(Publisher ignored) { return null; } @Override public SignalListener createListener(Publisher ignored1, ContextView listenerContext, Void ignored2) { return listenerGenerator.apply(listenerContext); } }); } /** * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} * {@link SignalListener} created by the provided {@link SignalListenerFactory}. *

* The factory will initialize a {@link SignalListenerFactory#initializePublisherState(Publisher) state object} for * each {@link Flux} or {@link Mono} instance it is used with, and that state will be cached and exposed for each * incoming {@link Subscriber} in order to generate the associated {@link SignalListenerFactory#createListener(Publisher, ContextView, Object) listener}. *

* Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} * the exception. *

* When the context-propagation library * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the library * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done * in conjunction with the use of {@link #contextCapture()} operator down the chain. * * @param listenerFactory the {@link SignalListenerFactory} to create a new {@link SignalListener} on each subscription * @return a new {@link Mono} with side effects defined by generated {@link SignalListener} * @see #tap(Supplier) * @see #tap(Function) */ public final Mono tap(SignalListenerFactory listenerFactory) { if (ContextPropagationSupport.shouldPropagateContextToThreadLocals()) { return onAssembly(new MonoTapRestoringThreadLocals<>(this, listenerFactory)); } if (this instanceof Fuseable) { return onAssembly(new MonoTapFuseable<>(this, listenerFactory)); } return onAssembly(new MonoTap<>(this, listenerFactory)); } /** * Return a {@code Mono} which only replays complete and error signals * from this {@link Mono}. * *

* * *

Discard Support: This operator discards the element from the source. * * @return a {@link Mono} ignoring its payload (actively dropping) */ public final Mono then() { return empty(this); } /** * Let this {@link Mono} complete then play another Mono. *

* In other words ignore element from this {@link Mono} and transform its completion signal into the * emission and completion signal of a provided {@code Mono}. Error signal is * replayed in the resulting {@code Mono}. * *

* * *

Discard Support: This operator discards the element from the source. * * @param other a {@link Mono} to emit from after termination * @param the element type of the supplied Mono * * @return a new {@link Mono} that emits from the supplied {@link Mono} */ public final Mono then(Mono other) { if (this instanceof MonoIgnoreThen) { MonoIgnoreThen a = (MonoIgnoreThen) this; return a.shift(other); } return onAssembly(new MonoIgnoreThen<>(new Publisher[] { this }, other)); } /** * Let this {@link Mono} complete successfully, then emit the provided value. On an error in the original {@link Mono}, the error signal is propagated instead. *

* * *

Discard Support: This operator discards the element from the source. * * @param value a value to emit after successful termination * @param the element type of the supplied value * * @return a new {@link Mono} that emits the supplied value */ public final Mono thenReturn(V value) { return then(Mono.just(value)); } /** * Return a {@code Mono} that waits for this {@link Mono} to complete then * for a supplied {@link Publisher Publisher<Void>} to also complete. The * second completion signal is replayed, or any error signal that occurs instead. *

* * *

Discard Support: This operator discards the element from the source. * * @param other a {@link Publisher} to wait for after this Mono's termination * @return a new {@link Mono} completing when both publishers have completed in * sequence */ public final Mono thenEmpty(Publisher other) { return then(fromDirect(other)); } /** * Let this {@link Mono} complete successfully then play another {@link Publisher}. On an error in the original {@link Mono}, the error signal is propagated instead. *

* In other words ignore the element from this mono and transform the completion signal into a * {@code Flux} that will emit elements from the provided {@link Publisher}. * *

* * *

Discard Support: This operator discards the element from the source. * * @param other a {@link Publisher} to emit from after termination * @param the element type of the supplied Publisher * * @return a new {@link Flux} that emits from the supplied {@link Publisher} after * this Mono completes. */ public final Flux thenMany(Publisher other) { @SuppressWarnings("unchecked") Flux concat = (Flux)Flux.concat(ignoreElement(), other); return Flux.onAssembly(concat); } /** * Times this {@link Mono} {@link Subscriber#onNext(Object)} event, encapsulated into a {@link Timed} object * that lets downstream consumer look at various time information gathered with nanosecond * resolution using the default clock ({@link Schedulers#parallel()}): *

    *
  • {@link Timed#elapsed()}: the time in nanoseconds since subscription, as a {@link Duration}. * This is functionally equivalent to {@link #elapsed()}, with a more expressive and precise * representation than a {@link Tuple2} with a long.
  • *
  • {@link Timed#timestamp()}: the timestamp of this onNext, as an {@link java.time.Instant} * (with nanoseconds part). This is functionally equivalent to {@link #timestamp()}, with a more * expressive and precise representation than a {@link Tuple2} with a long.
  • *
  • {@link Timed#elapsedSinceSubscription()}: for {@link Mono} this is the same as * {@link Timed#elapsed()}.
  • *
*

* The {@link Timed} object instances are safe to store and use later, as they are created as an * immutable wrapper around the {@code } value and immediately passed downstream. *

* * * @return a timed {@link Mono} * @see #elapsed() * @see #timestamp() */ public final Mono> timed() { return this.timed(Schedulers.parallel()); } /** * Times this {@link Mono} {@link Subscriber#onNext(Object)} event, encapsulated into a {@link Timed} object * that lets downstream consumer look at various time information gathered with nanosecond * resolution using the provided {@link Scheduler} as a clock: *

    *
  • {@link Timed#elapsed()}: the time in nanoseconds since subscription, as a {@link Duration}. * This is functionally equivalent to {@link #elapsed()}, with a more expressive and precise * representation than a {@link Tuple2} with a long.
  • *
  • {@link Timed#timestamp()}: the timestamp of this onNext, as an {@link java.time.Instant} * (with nanoseconds part). This is functionally equivalent to {@link #timestamp()}, with a more * expressive and precise representation than a {@link Tuple2} with a long.
  • *
  • {@link Timed#elapsedSinceSubscription()}: for {@link Mono} this is the same as * {@link Timed#elapsed()}.
  • *
*

* The {@link Timed} object instances are safe to store and use later, as they are created as an * immutable wrapper around the {@code } value and immediately passed downstream. *

* * * @return a timed {@link Mono} * @see #elapsed(Scheduler) * @see #timestamp(Scheduler) */ public final Mono> timed(Scheduler clock) { return onAssembly(new MonoTimed<>(this, clock)); } /** * Propagate a {@link TimeoutException} in case no item arrives within the given * {@link Duration}. * *

* * * @param timeout the timeout before the onNext signal from this {@link Mono} * * @return a {@link Mono} that can time out */ public final Mono timeout(Duration timeout) { return timeout(timeout, Schedulers.parallel()); } /** * Switch to a fallback {@link Mono} in case no item arrives within the given {@link Duration}. * *

* If the fallback {@link Mono} is null, signal a {@link TimeoutException} instead. * *

* * * @param timeout the timeout before the onNext signal from this {@link Mono} * @param fallback the fallback {@link Mono} to subscribe to when a timeout occurs * * @return a {@link Mono} that will fallback to a different {@link Mono} in case of timeout */ public final Mono timeout(Duration timeout, Mono fallback) { return timeout(timeout, fallback, Schedulers.parallel()); } /** * Signal a {@link TimeoutException} error in case an item doesn't arrive before the given period, * as measured on the provided {@link Scheduler}. * *

* * * @param timeout the timeout before the onNext signal from this {@link Mono} * @param timer a time-capable {@link Scheduler} instance to run the delay on * * @return an expirable {@link Mono} */ public final Mono timeout(Duration timeout, Scheduler timer) { return timeout(timeout, null, timer); } /** * Switch to a fallback {@link Mono} in case an item doesn't arrive before the given period, * as measured on the provided {@link Scheduler}. * *

If the given {@link Mono} is null, signal a {@link TimeoutException}. * *

* * * @param timeout the timeout before the onNext signal from this {@link Mono} * @param fallback the fallback {@link Mono} to subscribe when a timeout occurs * @param timer a time-capable {@link Scheduler} instance to run on * * @return an expirable {@link Mono} with a fallback {@link Mono} */ public final Mono timeout(Duration timeout, @Nullable Mono fallback, Scheduler timer) { final Mono _timer = Mono.delay(timeout, timer).onErrorReturn(0L); if(fallback == null) { return onAssembly(new MonoTimeout<>(this, _timer, timeout.toMillis() + "ms")); } return onAssembly(new MonoTimeout<>(this, _timer, fallback)); } /** * Signal a {@link TimeoutException} in case the item from this {@link Mono} has * not been emitted before the given {@link Publisher} emits. * *

* * * @param firstTimeout the timeout {@link Publisher} that must not emit before the first signal from this {@link Mono} * @param the element type of the timeout Publisher * * @return an expirable {@link Mono} if the item does not come before a {@link Publisher} signals * */ public final Mono timeout(Publisher firstTimeout) { return onAssembly(new MonoTimeout<>(this, firstTimeout, "first signal from a Publisher")); } /** * Switch to a fallback {@link Publisher} in case the item from this {@link Mono} has * not been emitted before the given {@link Publisher} emits. * *

* * * @param firstTimeout the timeout * {@link Publisher} that must not emit before the first signal from this {@link Mono} * @param fallback the fallback {@link Publisher} to subscribe when a timeout occurs * @param the element type of the timeout Publisher * * @return an expirable {@link Mono} with a fallback {@link Mono} if the item doesn't * come before a {@link Publisher} signals * */ public final Mono timeout(Publisher firstTimeout, Mono fallback) { return onAssembly(new MonoTimeout<>(this, firstTimeout, fallback)); } /** * If this {@link Mono} is valued, emit a {@link reactor.util.function.Tuple2} pair of * T1 the current clock time in millis (as a {@link Long} measured by the * {@link Schedulers#parallel() parallel} Scheduler) and T2 the emitted data (as a {@code T}). * *

* * * @return a timestamped {@link Mono} * @see #timed() */ public final Mono> timestamp() { return timestamp(Schedulers.parallel()); } /** * If this {@link Mono} is valued, emit a {@link reactor.util.function.Tuple2} pair of * T1 the current clock time in millis (as a {@link Long} measured by the * provided {@link Scheduler}) and T2 the emitted data (as a {@code T}). * *

The provider {@link Scheduler} will be asked to {@link Scheduler#now(TimeUnit) provide time} * with a granularity of {@link TimeUnit#MILLISECONDS}. In order for this operator to work as advertised, the * provided Scheduler should thus return results that can be interpreted as unix timestamps.

*

* * * * @param scheduler a {@link Scheduler} instance to read time from * @return a timestamped {@link Mono} * @see Scheduler#now(TimeUnit) * @see #timed(Scheduler) */ public final Mono> timestamp(Scheduler scheduler) { Objects.requireNonNull(scheduler, "scheduler"); return map(d -> Tuples.of(scheduler.now(TimeUnit.MILLISECONDS), d)); } /** * Transform this {@link Mono} into a {@link CompletableFuture} completing on onNext or onComplete and failing on * onError. * *

* * * @return a {@link CompletableFuture} */ public final CompletableFuture toFuture() { return subscribeWith(new MonoToCompletableFuture<>(false)); } /** * Transform this {@link Mono} in order to generate a target {@link Mono}. Unlike {@link #transformDeferred(Function)}, the * provided function is executed as part of assembly. * *

	 * Function applySchedulers = mono -> mono.subscribeOn(Schedulers.io())
	 *                                                    .publishOn(Schedulers.parallel());
	 * mono.transform(applySchedulers).map(v -> v * v).subscribe();
	 * 
*

* * * @param transformer the {@link Function} to immediately map this {@link Mono} into a target {@link Mono} * instance. * @param the item type in the returned {@link Mono} * * @return a new {@link Mono} * @see #transformDeferred(Function) transformDeferred(Function) for deferred composition of Mono for each Subscriber * @see #as(Function) as(Function) for a loose conversion to an arbitrary type */ @SuppressWarnings({"unchecked", "rawtypes"}) public final Mono transform(Function, ? extends Publisher> transformer) { if (Hooks.DETECT_CONTEXT_LOSS) { transformer = new ContextTrackingFunctionWrapper(transformer); } return onAssembly(from(transformer.apply(this))); } /** * Defer the given transformation to this {@link Mono} in order to generate a * target {@link Mono} type. A transformation will occur for each * {@link Subscriber}. For instance: * *

	 * mono.transformDeferred(original -> original.log());
	 * 
*

* * * @param transformer the {@link Function} to lazily map this {@link Mono} into a target {@link Mono} * instance upon subscription. * @param the item type in the returned {@link Publisher} * * @return a new {@link Mono} * @see #transform(Function) transform(Function) for immmediate transformation of Mono * @see #transformDeferredContextual(BiFunction) transformDeferredContextual(BiFunction) for a similarly deferred transformation of Mono reading the ContextView * @see #as(Function) as(Function) for a loose conversion to an arbitrary type */ public final Mono transformDeferred(Function, ? extends Publisher> transformer) { return defer(() -> { if (Hooks.DETECT_CONTEXT_LOSS) { @SuppressWarnings({"unchecked", "rawtypes"}) Mono result = from(new ContextTrackingFunctionWrapper((Function) transformer).apply(this)); return result; } return from(transformer.apply(this)); }); } /** * Defer the given transformation to this {@link Mono} in order to generate a * target {@link Mono} type. A transformation will occur for each * {@link Subscriber}. In addition, the transforming {@link BiFunction} exposes * the {@link ContextView} of each {@link Subscriber}. For instance: * *

	 * Mono<T> monoLogged = mono.transformDeferredContextual((original, ctx) -> original.log("for RequestID" + ctx.get("RequestID"))
	 * //...later subscribe. Each subscriber has its Context with a RequestID entry
	 * monoLogged.contextWrite(Context.of("RequestID", "requestA").subscribe();
	 * monoLogged.contextWrite(Context.of("RequestID", "requestB").subscribe();
	 * 
*

* * * @param transformer the {@link BiFunction} to lazily map this {@link Mono} into a target {@link Mono} * instance upon subscription, with access to {@link ContextView} * @param the item type in the returned {@link Publisher} * @return a new {@link Mono} * @see #transform(Function) transform(Function) for immmediate transformation of Mono * @see #transformDeferred(Function) transformDeferred(Function) for a similarly deferred transformation of Mono without the ContextView * @see #as(Function) as(Function) for a loose conversion to an arbitrary type */ public final Mono transformDeferredContextual(BiFunction, ? super ContextView, ? extends Publisher> transformer) { return deferContextual(ctxView -> { if (Hooks.DETECT_CONTEXT_LOSS) { ContextTrackingFunctionWrapper wrapper = new ContextTrackingFunctionWrapper<>( publisher -> transformer.apply(wrap(publisher, false), ctxView), transformer.toString() ); return wrap(wrapper.apply(this), true); } return from(transformer.apply(this, ctxView)); }); } /** * Wait for the result from this mono, use it to create a second mono via the * provided {@code rightGenerator} function and combine both results into a {@link Tuple2}. * *

* * * @param rightGenerator the {@link Function} to generate a {@code Mono} to combine with * @param the element type of the other Mono instance * * @return a new combined Mono */ public final Mono> zipWhen(Function> rightGenerator) { return zipWhen(rightGenerator, Tuples::of); } /** * Wait for the result from this mono, use it to create a second mono via the * provided {@code rightGenerator} function and combine both results into an arbitrary * {@code O} object, as defined by the provided {@code combinator} function. * *

* * * @param rightGenerator the {@link Function} to generate a {@code Mono} to combine with * @param combinator a {@link BiFunction} combinator function when both sources complete * @param the element type of the other Mono instance * @param the element type of the combination * * @return a new combined Mono */ public final Mono zipWhen(Function> rightGenerator, BiFunction combinator) { Objects.requireNonNull(rightGenerator, "rightGenerator function is mandatory to get the right-hand side Mono"); Objects.requireNonNull(combinator, "combinator function is mandatory to combine results from both Monos"); return flatMap(t -> rightGenerator.apply(t).map(t2 -> combinator.apply(t, t2))); } /** * Combine the result from this mono and another into a {@link Tuple2}. *

* An error or empty completion of any source will cause the other source * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* * * @param other the {@link Mono} to combine with * @param the element type of the other Mono instance * * @return a new combined Mono */ public final Mono> zipWith(Mono other) { return zipWith(other, Flux.tuple2Function()); } /** * Combine the result from this mono and another into an arbitrary {@code O} object, * as defined by the provided {@code combinator} function. *

* An error or empty completion of any source will cause the other source * to be cancelled and the resulting Mono to immediately error or complete, respectively. * *

* * * @param other the {@link Mono} to combine with * @param combinator a {@link BiFunction} combinator function when both sources * complete * @param the element type of the other Mono instance * @param the element type of the combination * * @return a new combined Mono */ public final Mono zipWith(Mono other, BiFunction combinator) { if (this instanceof MonoZip) { @SuppressWarnings("unchecked") MonoZip o = (MonoZip) this; Mono result = o.zipAdditionalSource(other, combinator); if (result != null) { return result; } } return zip(this, other, combinator); } /** * To be used by custom operators: invokes assembly {@link Hooks} pointcut given a * {@link Mono}, potentially returning a new {@link Mono}. This is for example useful * to activate cross-cutting concerns at assembly time, eg. a generalized * {@link #checkpoint()}. * * @param the value type * @param source the source to apply assembly hooks onto * * @return the source, potentially wrapped with assembly time cross-cutting behavior */ @SuppressWarnings("unchecked") protected static Mono onAssembly(Mono source) { Function hook = Hooks.onEachOperatorHook; if(hook != null) { source = (Mono) hook.apply(source); } if (Hooks.GLOBAL_TRACE) { AssemblySnapshot stacktrace = new AssemblySnapshot(null, Traces.callSiteSupplierFactory.get()); source = (Mono) Hooks.addAssemblyInfo(source, stacktrace); } return source; } @Override public String toString() { return getClass().getSimpleName(); } static Mono empty(Publisher source) { @SuppressWarnings("unchecked") Mono then = (Mono)ignoreElements(source); return then; } static Mono doOnSignal(Mono source, @Nullable Consumer onSubscribe, @Nullable Consumer onNext, @Nullable LongConsumer onRequest, @Nullable Runnable onCancel) { if (source instanceof Fuseable) { return onAssembly(new MonoPeekFuseable<>(source, onSubscribe, onNext, onRequest, onCancel)); } return onAssembly(new MonoPeek<>(source, onSubscribe, onNext, onRequest, onCancel)); } static Mono doOnTerminalSignal(Mono source, @Nullable Consumer onSuccess, @Nullable Consumer onError, @Nullable BiConsumer onAfterTerminate) { return onAssembly(new MonoPeekTerminal<>(source, onSuccess, onError, onAfterTerminate)); } /** * Unchecked wrap of {@link Publisher} as {@link Mono}, supporting {@link Fuseable} sources. * When converting a {@link Mono} or {@link Mono Monos} that have been converted to a {@link Flux} and back, * the original {@link Mono} is returned unwrapped. * Note that this bypasses {@link Hooks#onEachOperator(String, Function) assembly hooks}. * * @param source the {@link Publisher} to wrap * @param enforceMonoContract {@code true} to wrap publishers without assumption about their cardinality * (first {@link Subscriber#onNext(Object)} will cancel the source), {@code false} to behave like {@link #fromDirect(Publisher)}. * @param input upstream type * @return a wrapped {@link Mono} */ static Mono wrap(Publisher source, boolean enforceMonoContract) { //some sources can be considered already assembled monos //all conversion methods (from, fromDirect, wrap) must accommodate for this boolean shouldWrap = ContextPropagationSupport.shouldWrapPublisher(source); if (source instanceof Mono) { if (!shouldWrap) { return (Mono) source; } return ContextPropagation.monoRestoreThreadLocals((Mono) source); } if (source instanceof FluxSourceMono || source instanceof FluxSourceMonoFuseable) { @SuppressWarnings("unchecked") Mono extracted = (Mono) ((FluxFromMonoOperator) source).source; boolean shouldWrapExtracted = ContextPropagationSupport.shouldWrapPublisher(extracted); if (!shouldWrapExtracted) { return extracted; } return ContextPropagation.monoRestoreThreadLocals(extracted); } if (source instanceof Flux && source instanceof Callable) { @SuppressWarnings("unchecked") Callable m = (Callable) source; return Flux.wrapToMono(m); } Mono target; //equivalent to what from used to be, without assembly hooks if (enforceMonoContract) { if (source instanceof Flux) { target = new MonoNext<>((Flux) source); } else { target = new MonoFromPublisher<>(source); } //equivalent to what fromDirect used to be without onAssembly } else if (source instanceof Flux && source instanceof Fuseable) { target = new MonoSourceFluxFuseable<>((Flux) source); } else if (source instanceof Flux) { target = new MonoSourceFlux<>((Flux) source); } else if (source instanceof Fuseable) { target = new MonoSourceFuseable<>(source); } else { target = new MonoSource<>(source); } if (shouldWrap) { return ContextPropagation.monoRestoreThreadLocals(target); } return target; } @SuppressWarnings("unchecked") static BiPredicate equalsBiPredicate(){ return EQUALS_BIPREDICATE; } static final BiPredicate EQUALS_BIPREDICATE = Object::equals; }