From 4caacc993fb4cd4795a841ffbd3542597105f08a Mon Sep 17 00:00:00 2001 From: Vasiliy Mikhailov Date: Mon, 22 Jun 2026 08:22:08 +0300 Subject: [PATCH] Fix Scheduler.toExecutorService() NullPointerException from null worker store The no-arg toExecutorService() passed null for the SchedulerToExecutorService worker store, so every method (execute/submit/shutdown/isShutdown/...) threw NullPointerException on first use via workerStore.get(). Pass an empty AtomicReference<>() instead, matching the toExecutorService(boolean) overload; with no worker present the methods correctly fall back to scheduler.scheduleDirect(). Adds a regression test. --- .../io/reactivex/rxjava4/core/Scheduler.java | 2 +- .../reactivex/rxjava4/core/SchedulerTest.java | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/reactivex/rxjava4/core/Scheduler.java b/src/main/java/io/reactivex/rxjava4/core/Scheduler.java index 3529e6e6db..55badacf08 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Scheduler.java +++ b/src/main/java/io/reactivex/rxjava4/core/Scheduler.java @@ -389,7 +389,7 @@ public S when(@NonNull Function()); } /** diff --git a/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java b/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java index 4dfe195371..649c058209 100644 --- a/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java @@ -20,8 +20,12 @@ import org.junit.After; import org.junit.Test; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; +import io.reactivex.rxjava4.schedulers.Schedulers; + public class SchedulerTest { private static final String DRIFT_USE_NANOTIME = "rx4.scheduler.use-nanotime"; @@ -70,4 +74,19 @@ public void clockDriftCalculation() { assertEquals(300_000_000_000L, Scheduler.computeClockDrift(5, null)); } + @Test + public void toExecutorServiceWithoutWorkerExecutes() throws Exception { + // The no-arg toExecutorService() must return a usable ExecutorService that falls back to + // scheduleDirect() when there is no worker; it previously passed null for the worker store, + // so every method threw NullPointerException on first use. + ExecutorService exec = Schedulers.single().toExecutorService(); + try { + CountDownLatch latch = new CountDownLatch(1); + exec.execute(latch::countDown); + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertFalse(exec.isShutdown()); + } finally { + exec.shutdown(); + } + } }