@@ -43,7 +43,8 @@ Key capabilities include:
4343* **`Awaitable.go`, `AsyncChannel`, and `Awaitable.any`** — task spawning and channel-based communication primitives
4444* **Framework integration** — built-in adapters for `CompletableFuture` and `Future`;
4545`Flow.Publisher` support via an auto-discovered runtime adapter;
46- extensible to RxJava, Reactor, and Spring via the adapter registry
46+ drop-in Reactor and RxJava 3 modules (`groovy-reactor`, `groovy-rxjava`) with
47+ `ServiceLoader`-based auto-discovery; extensible to any framework via the adapter registry
4748
4849On JDK 21+, async methods automatically leverage
4950{jdk}/java.base/java/lang/Thread.html#ofVirtual()[virtual threads] for optimal scalability.
@@ -133,11 +134,12 @@ The `await` keyword natively understands `CompletableFuture`, `CompletionStage`,
133134include::../test/AsyncAwaitSpecTest.groovy[tags=motivation_interop,indent=0]
134135----
135136
136- For third-party frameworks like RxJava, Reactor, or Spring, the
137- `AwaitableAdapterRegistry` SPI allows registering custom adapters so that
138- `await` works transparently with _any_ asynchronous type — a single
139- `await` keyword is all the application code needs, regardless of the
140- underlying async library.
137+ For third-party frameworks like RxJava, Reactor, or Spring, Groovy provides
138+ dedicated adapter modules — `groovy-reactor` and `groovy-rxjava` — that are
139+ auto-discovered via `ServiceLoader` when placed on the classpath.
140+ No manual registration is required: simply add the dependency and `await`
141+ works transparently with `Mono`, `Flux`, `Single`, `Maybe`, `Observable`,
142+ and `Flowable`.
141143
142144=== Virtual Threads: Free Scalability
143145
@@ -798,18 +800,67 @@ include::../test/AsyncAwaitSpecTest.groovy[tags=adapter_registration,indent=0]
798800
799801=== Framework Integration
800802
801- With appropriate adapters registered, `await` works transparently with any async type.
802- Adapter implementations for frameworks such as RxJava 3, Project Reactor, and Spring
803- should delegate to the framework's native blocking or conversion methods:
803+ Groovy ships dedicated adapter modules for the two most popular JVM reactive frameworks.
804+ Adding either module to the classpath enables zero-configuration `async`/`await` support
805+ for that framework's types — no manual adapter registration is needed.
806+
807+ ==== Project Reactor (`groovy-reactor`)
808+
809+ The `groovy-reactor` module bridges Reactor's `Mono` and `Flux` into Groovy's async system:
810+
811+ * `Mono<T>` → `Awaitable<T>` — use `await(mono)` to resolve the single emitted value
812+ * `Flux<T>` → `AsyncStream<T>` — use `for await (item in flux)` to iterate over all values
813+
814+ [source,groovy]
815+ ----
816+ // Add to classpath — adapters are auto-discovered via ServiceLoader
817+ // Gradle: implementation "org.apache.groovy:groovy-reactor:${groovyVersion}"
818+
819+ async {
820+ def result = await Mono.just("hello") // single value
821+ for await (item in Flux.range(1, 5)) { use(item) } // multi-value
822+ }
823+ ----
824+
825+ For comprehensive documentation including operators, Spring WebFlux integration, and
826+ `Awaitable` combinators, see the <<reactor-userguide,Project Reactor Integration>> guide.
827+
828+ ==== RxJava 3 (`groovy-rxjava`)
829+
830+ The `groovy-rxjava` module bridges RxJava 3's types into Groovy's async system:
831+
832+ * `Single<T>` / `Maybe<T>` → `Awaitable<T>` — use `await(single)` or `await(maybe)`
833+ * `Observable<T>` / `Flowable<T>` → `AsyncStream<T>` — use `for await (item in source)`
834+
835+ [source,groovy]
836+ ----
837+ // Add to classpath — adapters are auto-discovered via ServiceLoader
838+ // Gradle: implementation "org.apache.groovy:groovy-rxjava:${groovyVersion}"
839+
840+ async {
841+ def result = await Single.just("hello") // single value
842+ for await (item in Observable.range(1, 5)) { use(item) } // multi-value
843+ }
844+ ----
845+
846+ For comprehensive documentation including `Maybe`, `Flowable`, back-pressure, and
847+ `Awaitable` combinators, see the <<rxjava-userguide,RxJava 3 Integration>> guide.
848+
849+ ==== Custom Adapters for Other Frameworks
850+
851+ For frameworks not covered by the built-in modules, implement the `AwaitableAdapter` interface
852+ and delegate to the framework's native blocking or conversion methods:
804853
805- * **RxJava 3**: `Single.blockingGet()`, `Observable.blockingIterable()` (for `AsyncStream`)
806- * **Reactor**: `Mono.block()`, `Flux.toIterable()` (for `AsyncStream`)
807854* **Spring**: Return `Awaitable` from `@Async` service methods; adapt `ListenableFuture` via `toCompletableFuture()`
855+ * **Vert.x**: Adapt `io.vertx.core.Future` via `toCompletionStage()`
808856
809857=== Automatic Discovery
810858
811- Adapters can also be discovered automatically via `java.util.ServiceLoader` by placing a
859+ Adapters are discovered automatically via `java.util.ServiceLoader` by placing a
812860provider configuration file at `META-INF/services/groovy.concurrent.AwaitableAdapter`.
861+ The `groovy-reactor` and `groovy-rxjava` modules use this mechanism — adding them to the
862+ classpath is sufficient for transparent integration.
863+
813864SPI-discovered adapters are loaded at class-initialization time and take priority over
814865the built-in adapters. Runtime-registered adapters (via `register()`) take highest
815866priority, allowing application code to override any default.
@@ -1356,7 +1407,7 @@ JavaScript, C#, Kotlin, and Swift, for developers familiar with those languages.
13561407
13571408| **Async iteration**
13581409| `for await (x in src) { }` +
1359- _(supports `AsyncStream`, `Flow.Publisher`, `AsyncChannel`, `Iterable`)_
1410+ _(supports `AsyncStream`, `Flow.Publisher`, `AsyncChannel`, `Iterable`, Reactor `Flux`, RxJava `Observable`/`Flowable` )_
13601411| `for await (x of src) { }`
13611412| `await foreach (x in src) { }`
13621413| _(manual via `Flow`, `AsyncChannel`, or `Flow.collect`)_
@@ -1452,7 +1503,8 @@ _(supports `AsyncStream`, `Flow.Publisher`, `AsyncChannel`, `Iterable`)_
14521503
14531504| **Third-party support**
14541505| `AwaitableAdapterRegistry` SPI +
1455- `Awaitable.from()` / `AsyncStream.from()`
1506+ `Awaitable.from()` / `AsyncStream.from()` +
1507+ Built-in modules: `groovy-reactor`, `groovy-rxjava`
14561508| _(native `thenable` protocol)_
14571509| Custom awaiters via `GetAwaiter()`
14581510| coroutine adapters / bridges
@@ -2029,4 +2081,10 @@ For full javadoc, see the API documentation for the `groovy.concurrent` package.
20292081
20302082| Executor configuration
20312083| `Awaitable.setExecutor(myExecutor)` / system property `groovy.async.parallelism`
2084+
2085+ | Reactor integration
2086+ | Add `groovy-reactor` to classpath; `await(mono)` / `for await (x in flux)`
2087+
2088+ | RxJava 3 integration
2089+ | Add `groovy-rxjava` to classpath; `await(single)` / `for await (x in observable)`
20322090|===
0 commit comments