Repository: redis/lettuce
Pull request #3170 (2025-02-08 14:39:36)

report block error when use with reactor mode #3168 (6.5.x)
<!--
Thank you for proposing a pull request. This template will guide you through the essential steps necessary for a pull request.
-->
Crossport #3168 to 6.5.x

Make sure that:

- [x] You have read the [contribution guidelines](https://github.com/lettuce-io/lettuce-core/blob/main/.github/CONTRIBUTING.md).
- [x] You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
- [x] You applied code formatting rules using the `mvn formatter:format` target. Don’t submit any formatting related changes.
- [x] You submit test cases (unit or integration tests) that back your changes.

 <!--
Great! Live long and prosper.
-->



Patch:
diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
index 48ebae4ed..ccacbfdef 100644
--- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
+++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
@@ -48,7 +48,6 @@ import io.lettuce.core.protocol.CommandArgs;
 import io.lettuce.core.protocol.CommandType;
 import io.lettuce.core.protocol.ProtocolKeyword;
 import io.lettuce.core.protocol.RedisCommand;
-import reactor.core.publisher.Mono;
 
 import java.time.Duration;
 import java.time.Instant;
@@ -56,6 +55,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import static io.lettuce.core.ClientOptions.DEFAULT_JSON_PARSER;
 import static io.lettuce.core.protocol.CommandType.EXEC;
@@ -87,7 +87,7 @@ public abstract class AbstractRedisAsyncCommands<K, V> implements RedisAclAsyncC
 
     private final RedisJsonCommandBuilder<K, V> jsonCommandBuilder;
 
-    private final Mono<JsonParser> parser;
+    private final Supplier<JsonParser> parser;
 
     /**
      * Initialize a new instance.
@@ -96,7 +96,8 @@ public abstract class AbstractRedisAsyncCommands<K, V> implements RedisAclAsyncC
      * @param codec the codec for command encoding
      * @param parser the implementation of the {@link JsonParser} to use
      */
-    public AbstractRedisAsyncCommands(StatefulConnection<K, V> connection, RedisCodec<K, V> codec, Mono<JsonParser> parser) {
+    public AbstractRedisAsyncCommands(StatefulConnection<K, V> connection, RedisCodec<K, V> codec,
+            Supplier<JsonParser> parser) {
         this.parser = parser;
         this.connection = connection;
         this.commandBuilder = new RedisCommandBuilder<>(codec);
@@ -3391,7 +3392,7 @@ public abstract class AbstractRedisAsyncCommands<K, V> implements RedisAclAsyncC
 
     @Override
     public JsonParser getJsonParser() {
-        return this.parser.block();
+        return this.parser.get();
     }
 
     private byte[] encodeFunction(String functionCode) {
diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
index 9732aeaae..ce0a6a386 100644
--- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
+++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
@@ -97,7 +97,7 @@ public abstract class AbstractRedisReactiveCommands<K, V>
 
     private final RedisJsonCommandBuilder<K, V> jsonCommandBuilder;
 
-    private final Mono<JsonParser> parser;
+    private final Supplier<JsonParser> parser;
 
     private final ClientResources clientResources;
 
@@ -112,7 +112,8 @@ public abstract class AbstractRedisReactiveCommands<K, V>
      * @param codec the codec for command encoding.
      * @param parser the implementation of the {@link JsonParser} to use
      */
-    public AbstractRedisReactiveCommands(StatefulConnection<K, V> connection, RedisCodec<K, V> codec, Mono<JsonParser> parser) {
+    public AbstractRedisReactiveCommands(StatefulConnection<K, V> connection, RedisCodec<K, V> codec,
+            Supplier<JsonParser> parser) {
         this.connection = connection;
         this.parser = parser;
         this.commandBuilder = new RedisCommandBuilder<>(codec);
@@ -149,7 +150,7 @@ public abstract class AbstractRedisReactiveCommands<K, V>
 
     @Override
     public JsonParser getJsonParser() {
-        return parser.block();
+        return parser.get();
     }
 
     @Override
diff --git a/src/main/java/io/lettuce/core/ClientOptions.java b/src/main/java/io/lettuce/core/ClientOptions.java
index 9f1f1c33d..5d1e2160d 100644
--- a/src/main/java/io/lettuce/core/ClientOptions.java
+++ b/src/main/java/io/lettuce/core/ClientOptions.java
@@ -25,6 +25,7 @@ import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 
 import io.lettuce.core.api.StatefulConnection;
 import io.lettuce.core.internal.LettuceAssert;
@@ -69,7 +70,7 @@ public class ClientOptions implements Serializable {
 
     public static final SocketOptions DEFAULT_SOCKET_OPTIONS = SocketOptions.create();
 
-    public static final Mono<JsonParser> DEFAULT_JSON_PARSER = Mono.defer(() -> Mono.fromCallable(() -> {
+    public static final Supplier<JsonParser> DEFAULT_JSON_PARSER = () -> {
         try {
             Iterator<JsonParser> services = ServiceLoader.load(JsonParser.class).iterator();
             return services.hasNext() ? services.next() : null;
@@ -77,7 +78,7 @@ public class ClientOptions implements Serializable {
             throw new RedisJsonException("Could not load JsonParser, please consult the guide"
                     + "at https://redis.github.io/lettuce/user-guide/redis-json/", e);
         }
-    }));
+    };
 
     public static final SslOptions DEFAULT_SSL_OPTIONS = SslOptions.create();
 
@@ -105,7 +106,7 @@ public class ClientOptions implements Serializable {
 
     private final Charset scriptCharset;
 
-    private final Mono<JsonParser> jsonParser;
+    private final Supplier<JsonParser> jsonParser;
 
     private final SocketOptions socketOptions;
 
@@ -204,7 +205,7 @@ public class ClientOptions implements Serializable {
 
         private Charset scriptCharset = DEFAULT_SCRIPT_CHARSET;
 
-        private Mono<JsonParser> jsonParser = DEFAULT_JSON_PARSER;
+        private Supplier<JsonParser> jsonParser = DEFAULT_JSON_PARSER;
 
         private SocketOptions socketOptions = DEFAULT_SOCKET_OPTIONS;
 
@@ -399,7 +400,7 @@ public class ClientOptions implements Serializable {
          * @see JsonParser
          * @since 6.5
          */
-        public Builder jsonParser(Mono<JsonParser> parser) {
+        public Builder jsonParser(Supplier<JsonParser> parser) {
 
             LettuceAssert.notNull(parser, "JsonParser must not be null");
             this.jsonParser = parser;
@@ -652,7 +653,7 @@ public class ClientOptions implements Serializable {
      * @return the implementation of the {@link JsonParser} to use.
      * @since 6.5
      */
-    public Mono<JsonParser> getJsonParser() {
+    public Supplier<JsonParser> getJsonParser() {
         return jsonParser;
     }
 
diff --git a/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java b/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java
index 87bae13e0..4e2075519 100644
--- a/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java
+++ b/src/main/java/io/lettuce/core/RedisAsyncCommandsImpl.java
@@ -5,7 +5,7 @@ import io.lettuce.core.api.async.RedisAsyncCommands;
 import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands;
 import io.lettuce.core.codec.RedisCodec;
 import io.lettuce.core.json.JsonParser;
-import reactor.core.publisher.Mono;
+import java.util.function.Supplier;
 
 /**
  * An asynchronous and thread-safe API for a Redis connection.
@@ -24,7 +24,8 @@ public class RedisAsyncCommandsImpl<K, V> extends AbstractRedisAsyncCommands<K,
      * @param codec the codec for command encoding
      * @param parser the implementation of the {@link JsonParser} to use
      */
-    public RedisAsyncCommandsImpl(StatefulRedisConnection<K, V> connection, RedisCodec<K, V> codec, Mono<JsonParser> parser) {
+    public RedisAsyncCommandsImpl(StatefulRedisConnection<K, V> connection, RedisCodec<K, V> codec,
+            Supplier<JsonParser> parser) {
         super(connection, codec, parser);
     }
 
diff --git a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
index ee7e8cf97..9aff2e594 100644
--- a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
+++ b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
@@ -20,9 +20,9 @@ import io.lettuce.core.output.*;
 import io.lettuce.core.protocol.BaseRedisCommandBuilder;
 import io.lettuce.core.protocol.Command;
 import io.lettuce.core.protocol.CommandArgs;
-import reactor.core.publisher.Mono;
 
 import java.util.List;
+import java.util.function.Supplier;
 
 import static io.lettuce.core.protocol.CommandType.*;
 
@@ -34,9 +34,9 @@ import static io.lettuce.core.protocol.CommandType.*;
  */
 class RedisJsonCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {
 
-    private final Mono<JsonParser> parser;
+    private final Supplier<JsonParser> parser;
 
-    RedisJsonCommandBuilder(RedisCodec<K, V> codec, Mono<JsonParser> theParser) {
+    RedisJsonCommandBuilder(RedisCodec<K, V> codec, Supplier<JsonParser> theParser) {
         super(codec);
         parser = theParser;
     }
@@ -118,7 +118,7 @@ class RedisJsonCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {
             }
         }
 
-        return createCommand(JSON_ARRPOP, new JsonValueListOutput<>(codec, parser.block()), args);
+        return createCommand(JSON_ARRPOP, new JsonValueListOutput<>(codec, parser.get()), args);
     }
 
     Command<K, V, List<Long>> jsonArrtrim(K key, JsonPath jsonPath, JsonRangeArgs range) {
@@ -167,7 +167,7 @@ class RedisJsonCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {
             }
         }
 
-        return createCommand(JSON_GET, new JsonValueListOutput<>(codec, parser.block()), args);
+        return createCommand(JSON_GET, new JsonValueListOutput<>(codec, parser.get()), args);
     }
 
     Command<K, V, String> jsonMerge(K key, JsonPath jsonPath, JsonValue value) {
@@ -194,7 +194,7 @@ class RedisJsonCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {
             args.add(jsonPath.toString());
         }
 
-        return createCommand(JSON_MGET, new JsonValueListOutput<>(codec, parser.block()), args);
+        return createCommand(JSON_MGET, new JsonValueListOutput<>(codec, parser.get()), args);
     }
 
     Command<K, V, String> jsonMSet(List<JsonMsetArgs<K, V>> arguments) {
diff --git a/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java b/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java
index de0195739..620b5510a 100644
--- a/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java
+++ b/src/main/java/io/lettuce/core/RedisReactiveCommandsImpl.java
@@ -7,6 +7,8 @@ import io.lettuce.core.codec.RedisCodec;
 import io.lettuce.core.json.JsonParser;
 import reactor.core.publisher.Mono;
 
+import java.util.function.Supplier;
+
 /**
  * A reactive and thread-safe API for a Redis Sentinel connection.
  *
@@ -25,7 +27,7 @@ public class RedisReactiveCommandsImpl<K, V> extends AbstractRedisReactiveComman
      * @param parser the implementation of the {@link JsonParser} to use
      */
     public RedisReactiveCommandsImpl(StatefulRedisConnection<K, V> connection, RedisCodec<K, V> codec,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         super(connection, codec, parser);
     }
 
diff --git a/src/main/java/io/lettuce/core/StatefulRedisConnectionImpl.java b/src/main/java/io/lettuce/core/StatefulRedisConnectionImpl.java
index 14ba7b570..b6c7f6e89 100644
--- a/src/main/java/io/lettuce/core/StatefulRedisConnectionImpl.java
+++ b/src/main/java/io/lettuce/core/StatefulRedisConnectionImpl.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import io.lettuce.core.api.StatefulRedisConnection;
@@ -67,7 +68,7 @@ public class StatefulRedisConnectionImpl<K, V> extends RedisChannelHandler<K, V>
 
     private final PushHandler pushHandler;
 
-    private final Mono<JsonParser> parser;
+    private final Supplier<JsonParser> parser;
 
     protected MultiOutput<K, V> multi;
 
@@ -94,7 +95,7 @@ public class StatefulRedisConnectionImpl<K, V> extends RedisChannelHandler<K, V>
      * @param parser the parser to use for JSON commands.
      */
     public StatefulRedisConnectionImpl(RedisChannelWriter writer, PushHandler pushHandler, RedisCodec<K, V> codec,
-            Duration timeout, Mono<JsonParser> parser) {
+            Duration timeout, Supplier<JsonParser> parser) {
 
         super(writer, timeout);
 
diff --git a/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterAsyncCommandsImpl.java b/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterAsyncCommandsImpl.java
index 840a6ef1f..d8f8e4092 100644
--- a/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterAsyncCommandsImpl.java
+++ b/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterAsyncCommandsImpl.java
@@ -29,13 +29,13 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import io.lettuce.core.*;
@@ -64,7 +64,6 @@ import io.lettuce.core.protocol.AsyncCommand;
 import io.lettuce.core.protocol.Command;
 import io.lettuce.core.protocol.CommandType;
 import io.lettuce.core.protocol.ConnectionIntent;
-import reactor.core.publisher.Mono;
 
 /**
  * An advanced asynchronous and thread-safe API for a Redis Cluster connection.
@@ -89,11 +88,11 @@ public class RedisAdvancedClusterAsyncCommandsImpl<K, V> extends AbstractRedisAs
      * @param codec Codec used to encode/decode keys and values.
      * @param parser the implementation of the {@link JsonParser} to use
      * @deprecated since 5.1, use
-     *             {@link #RedisAdvancedClusterAsyncCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Mono)}.
+     *             {@link #RedisAdvancedClusterAsyncCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Supplier)}.
      */
     @Deprecated
     public RedisAdvancedClusterAsyncCommandsImpl(StatefulRedisClusterConnectionImpl<K, V> connection, RedisCodec<K, V> codec,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         super(connection, codec, parser);
         this.codec = codec;
     }
@@ -104,7 +103,7 @@ public class RedisAdvancedClusterAsyncCommandsImpl<K, V> extends AbstractRedisAs
      * @param connection the stateful connection
      * @param codec Codec used to encode/decode keys and values.
      * @deprecated since 5.1, use
-     *             {@link #RedisAdvancedClusterAsyncCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Mono)}.
+     *             {@link #RedisAdvancedClusterAsyncCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Supplier)}.
      */
     @Deprecated
     public RedisAdvancedClusterAsyncCommandsImpl(StatefulRedisClusterConnectionImpl<K, V> connection, RedisCodec<K, V> codec) {
@@ -120,7 +119,7 @@ public class RedisAdvancedClusterAsyncCommandsImpl<K, V> extends AbstractRedisAs
      * @param parser the implementation of the {@link JsonParser} to use
      */
     public RedisAdvancedClusterAsyncCommandsImpl(StatefulRedisClusterConnection<K, V> connection, RedisCodec<K, V> codec,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         super(connection, codec, parser);
         this.codec = codec;
     }
diff --git a/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterReactiveCommandsImpl.java
index 0fa184b37..36d211fb3 100644
--- a/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterReactiveCommandsImpl.java
+++ b/src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterReactiveCommandsImpl.java
@@ -32,6 +32,7 @@ import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import io.lettuce.core.json.JsonParser;
@@ -78,11 +79,11 @@ public class RedisAdvancedClusterReactiveCommandsImpl<K, V> extends AbstractRedi
      * @param codec Codec used to encode/decode keys and values.
      * @param parser the implementation of the {@link JsonParser} to use
      * @deprecated since 5.2, use
-     *             {@link #RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Mono)}.
+     *             {@link #RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Supplier)}.
      */
     @Deprecated
     public RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnectionImpl<K, V> connection, RedisCodec<K, V> codec,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         super(connection, codec, parser);
         this.codec = codec;
     }
@@ -93,7 +94,7 @@ public class RedisAdvancedClusterReactiveCommandsImpl<K, V> extends AbstractRedi
      * @param connection the stateful connection.
      * @param codec Codec used to encode/decode keys and values.
      * @deprecated since 5.2, use
-     *             {@link #RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Mono)}.
+     *             {@link #RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnection, RedisCodec, Supplier)}.
      */
     @Deprecated
     public RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnectionImpl<K, V> connection,
@@ -110,7 +111,7 @@ public class RedisAdvancedClusterReactiveCommandsImpl<K, V> extends AbstractRedi
      * @param parser the implementation of the {@link JsonParser} to use
      */
     public RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnection<K, V> connection, RedisCodec<K, V> codec,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         super(connection, codec, parser);
         this.codec = codec;
     }
diff --git a/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java b/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
index c5ef64c70..3c0c8729d 100644
--- a/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
+++ b/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
@@ -582,7 +582,7 @@ public class RedisClusterClient extends AbstractRedisClient {
      * @return new instance of StatefulRedisConnectionImpl
      */
     protected <K, V> StatefulRedisConnectionImpl<K, V> newStatefulRedisConnection(RedisChannelWriter channelWriter,
-            PushHandler pushHandler, RedisCodec<K, V> codec, Duration timeout, Mono<JsonParser> parser) {
+            PushHandler pushHandler, RedisCodec<K, V> codec, Duration timeout, Supplier<JsonParser> parser) {
         return new StatefulRedisConnectionImpl<>(channelWriter, pushHandler, codec, timeout, parser);
     }
 
@@ -726,7 +726,7 @@ public class RedisClusterClient extends AbstractRedisClient {
      */
     protected <V, K> StatefulRedisClusterConnectionImpl<K, V> newStatefulRedisClusterConnection(
             RedisChannelWriter channelWriter, ClusterPushHandler pushHandler, RedisCodec<K, V> codec, Duration timeout,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         return new StatefulRedisClusterConnectionImpl(channelWriter, pushHandler, codec, timeout, parser);
     }
 
diff --git a/src/main/java/io/lettuce/core/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/io/lettuce/core/cluster/StatefulRedisClusterConnectionImpl.java
index c84193491..d967ada1e 100644
--- a/src/main/java/io/lettuce/core/cluster/StatefulRedisClusterConnectionImpl.java
+++ b/src/main/java/io/lettuce/core/cluster/StatefulRedisClusterConnectionImpl.java
@@ -30,6 +30,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import io.lettuce.core.AbstractRedisClient;
@@ -77,7 +78,7 @@ public class StatefulRedisClusterConnectionImpl<K, V> extends RedisChannelHandle
 
     protected final RedisCodec<K, V> codec;
 
-    protected final Mono<JsonParser> parser;
+    protected final Supplier<JsonParser> parser;
 
     protected final RedisAdvancedClusterCommands<K, V> sync;
 
@@ -113,7 +114,7 @@ public class StatefulRedisClusterConnectionImpl<K, V> extends RedisChannelHandle
      * @param parser the JSON parser
      */
     public StatefulRedisClusterConnectionImpl(RedisChannelWriter writer, ClusterPushHandler pushHandler, RedisCodec<K, V> codec,
-            Duration timeout, Mono<JsonParser> parser) {
+            Duration timeout, Supplier<JsonParser> parser) {
 
         super(writer, timeout);
         this.pushHandler = pushHandler;
diff --git a/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnectionImpl.java b/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnectionImpl.java
index ad1b5a53f..babafd51e 100644
--- a/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnectionImpl.java
+++ b/src/main/java/io/lettuce/core/masterreplica/StatefulRedisMasterReplicaConnectionImpl.java
@@ -1,12 +1,12 @@
 package io.lettuce.core.masterreplica;
 
 import java.time.Duration;
+import java.util.function.Supplier;
 
 import io.lettuce.core.ReadFrom;
 import io.lettuce.core.StatefulRedisConnectionImpl;
 import io.lettuce.core.codec.RedisCodec;
 import io.lettuce.core.json.JsonParser;
-import reactor.core.publisher.Mono;
 
 import static io.lettuce.core.ClientOptions.DEFAULT_JSON_PARSER;
 
@@ -36,7 +36,7 @@ class StatefulRedisMasterReplicaConnectionImpl<K, V> extends StatefulRedisConnec
      * @param parser the JSON parser to use
      */
     StatefulRedisMasterReplicaConnectionImpl(MasterReplicaChannelWriter writer, RedisCodec<K, V> codec, Duration timeout,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         super(writer, NoOpPushHandler.INSTANCE, codec, timeout, parser);
     }
 
diff --git a/src/main/java/io/lettuce/core/sentinel/RedisSentinelReactiveCommandsImpl.java b/src/main/java/io/lettuce/core/sentinel/RedisSentinelReactiveCommandsImpl.java
index e02cf4d96..af5937d4e 100644
--- a/src/main/java/io/lettuce/core/sentinel/RedisSentinelReactiveCommandsImpl.java
+++ b/src/main/java/io/lettuce/core/sentinel/RedisSentinelReactiveCommandsImpl.java
@@ -21,6 +21,7 @@ package io.lettuce.core.sentinel;
 
 import java.net.SocketAddress;
 import java.util.Map;
+import java.util.function.Supplier;
 
 import io.lettuce.core.AbstractRedisReactiveCommands;
 import io.lettuce.core.ClientListArgs;
@@ -52,7 +53,7 @@ public class RedisSentinelReactiveCommandsImpl<K, V> extends AbstractRedisReacti
     private final SentinelCommandBuilder<K, V> commandBuilder;
 
     public RedisSentinelReactiveCommandsImpl(StatefulConnection<K, V> connection, RedisCodec<K, V> codec,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         super(connection, codec, parser);
         commandBuilder = new SentinelCommandBuilder<K, V>(codec);
     }
diff --git a/src/main/java/io/lettuce/core/sentinel/StatefulRedisSentinelConnectionImpl.java b/src/main/java/io/lettuce/core/sentinel/StatefulRedisSentinelConnectionImpl.java
index f5a9a9c62..2eb209046 100644
--- a/src/main/java/io/lettuce/core/sentinel/StatefulRedisSentinelConnectionImpl.java
+++ b/src/main/java/io/lettuce/core/sentinel/StatefulRedisSentinelConnectionImpl.java
@@ -21,6 +21,7 @@ package io.lettuce.core.sentinel;
 
 import java.time.Duration;
 import java.util.Collection;
+import java.util.function.Supplier;
 
 import io.lettuce.core.ConnectionState;
 import io.lettuce.core.RedisChannelHandler;
@@ -34,7 +35,6 @@ import io.lettuce.core.sentinel.api.StatefulRedisSentinelConnection;
 import io.lettuce.core.sentinel.api.async.RedisSentinelAsyncCommands;
 import io.lettuce.core.sentinel.api.reactive.RedisSentinelReactiveCommands;
 import io.lettuce.core.sentinel.api.sync.RedisSentinelCommands;
-import reactor.core.publisher.Mono;
 
 import static io.lettuce.core.ClientOptions.DEFAULT_JSON_PARSER;
 
@@ -74,7 +74,7 @@ public class StatefulRedisSentinelConnectionImpl<K, V> extends RedisChannelHandl
      * @param parser the parser used to parse JSON responses
      */
     public StatefulRedisSentinelConnectionImpl(RedisChannelWriter writer, RedisCodec<K, V> codec, Duration timeout,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
 
         super(writer, timeout);
 


Test patch:
diff --git a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClusterClient.java b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClusterClient.java
index 1ac284807..f0d738336 100644
--- a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClusterClient.java
+++ b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClusterClient.java
@@ -20,6 +20,7 @@
 package biz.paluch.redis.extensibility;
 
 import java.time.Duration;
+import java.util.function.Supplier;
 
 import javax.enterprise.inject.Alternative;
 
@@ -51,7 +52,7 @@ public class MyExtendedRedisClusterClient extends RedisClusterClient {
     @Override
     protected <V, K> StatefulRedisClusterConnectionImpl<K, V> newStatefulRedisClusterConnection(
             RedisChannelWriter channelWriter, ClusterPushHandler pushHandler, RedisCodec<K, V> codec, Duration timeout,
-            Mono<JsonParser> parser) {
+            Supplier<JsonParser> parser) {
         return new MyRedisClusterConnection<>(channelWriter, pushHandler, codec, timeout, parser);
     }
 
diff --git a/src/test/java/biz/paluch/redis/extensibility/MyRedisClusterConnection.java b/src/test/java/biz/paluch/redis/extensibility/MyRedisClusterConnection.java
index 04632e463..a1152b976 100644
--- a/src/test/java/biz/paluch/redis/extensibility/MyRedisClusterConnection.java
+++ b/src/test/java/biz/paluch/redis/extensibility/MyRedisClusterConnection.java
@@ -20,6 +20,7 @@
 package biz.paluch.redis.extensibility;
 
 import java.time.Duration;
+import java.util.function.Supplier;
 
 import io.lettuce.core.RedisChannelWriter;
 import io.lettuce.core.cluster.ClusterPushHandler;
@@ -37,7 +38,7 @@ import reactor.core.publisher.Mono;
 class MyRedisClusterConnection<K, V> extends StatefulRedisClusterConnectionImpl<K, V> {
 
     public MyRedisClusterConnection(RedisChannelWriter writer, ClusterPushHandler pushHandler, RedisCodec<K, V> codec,
-            Duration timeout, Mono<JsonParser> parser) {
+            Duration timeout, Supplier<JsonParser> parser) {
         super(writer, pushHandler, codec, timeout, parser);
     }
 
diff --git a/src/test/java/io/lettuce/core/ClientOptionsUnitTests.java b/src/test/java/io/lettuce/core/ClientOptionsUnitTests.java
index bb2d0f91a..49811ea5c 100644
--- a/src/test/java/io/lettuce/core/ClientOptionsUnitTests.java
+++ b/src/test/java/io/lettuce/core/ClientOptionsUnitTests.java
@@ -40,7 +40,7 @@ class ClientOptionsUnitTests {
         assertThat(options.getReadOnlyCommands().isReadOnly(new Command<>(CommandType.SET, null))).isFalse();
         assertThat(options.getReadOnlyCommands().isReadOnly(new Command<>(CommandType.PUBLISH, null))).isFalse();
         assertThat(options.getReadOnlyCommands().isReadOnly(new Command<>(CommandType.GET, null))).isTrue();
-        assertThat(options.getJsonParser().block()).isInstanceOf(DefaultJsonParser.class);
+        assertThat(options.getJsonParser().get()).isInstanceOf(DefaultJsonParser.class);
     }
 
     @Test
@@ -66,8 +66,8 @@ class ClientOptionsUnitTests {
     @Test
     void jsonParser() {
         JsonParser parser = new CustomJsonParser();
-        ClientOptions options = ClientOptions.builder().jsonParser(Mono.justOrEmpty(parser)).build();
-        assertThat(options.getJsonParser().block()).isInstanceOf(CustomJsonParser.class);
+        ClientOptions options = ClientOptions.builder().jsonParser(() -> parser).build();
+        assertThat(options.getJsonParser().get()).isInstanceOf(CustomJsonParser.class);
     }
 
     static class CustomJsonParser implements JsonParser {
diff --git a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java
index 4106a711c..22f3aed34 100644
--- a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java
+++ b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java
@@ -49,7 +49,7 @@ class RedisJsonCommandBuilderUnitTests {
 
     public static final JsonPath MY_PATH = JsonPath.of("$..commuter_bikes");
 
-    RedisJsonCommandBuilder<String, String> builder = new RedisJsonCommandBuilder<>(StringCodec.UTF8, Mono.just(PARSER));
+    RedisJsonCommandBuilder<String, String> builder = new RedisJsonCommandBuilder<>(StringCodec.UTF8, () -> PARSER);
 
     @Test
     void shouldCorrectlyConstructJsonArrappend() {
diff --git a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
index 76fdd0661..b8d4ac924 100644
--- a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
+++ b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
@@ -601,7 +601,7 @@ public class RedisJsonIntegrationTests extends RedisContainerIntegrationTests {
         RedisURI redisURI = RedisURI.Builder.redis("127.0.0.1").withPort(16379).build();
 
         try (RedisClient client = RedisClient.create(redisURI)) {
-            client.setOptions(ClientOptions.builder().jsonParser(Mono.just(new CustomParser())).build());
+            client.setOptions(ClientOptions.builder().jsonParser(CustomParser::new).build());
             StatefulRedisConnection<String, String> connection = client.connect(StringCodec.UTF8);
             RedisCommands<String, String> redis = connection.sync();
             assertThat(redis.getJsonParser()).isInstanceOf(CustomParser.class);