Repository: redis/lettuce
Pull request #3165 (2025-02-06 06:43:01)

Bump default client-libs-test container version

Make sure that:

- [ ] You have read the [contribution guidelines](https://github.com/lettuce-io/lettuce-core/blob/main/.github/CONTRIBUTING.md).
- [ ] You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
- [ ] You applied code formatting rules using the `mvn formatter:format` target. Don’t submit any formatting related changes.
- [ ] 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 de095893f..fd1ad55eb 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);
@@ -3396,7 +3397,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 1e9365821..e1651e562 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 3fd635e4e..5c02c3b18 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;
@@ -71,7 +72,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;
@@ -79,7 +80,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();
 
@@ -111,7 +112,7 @@ public class ClientOptions implements Serializable {
 
     private final Charset scriptCharset;
 
-    private final Mono<JsonParser> jsonParser;
+    private final Supplier<JsonParser> jsonParser;
 
     private final SocketOptions socketOptions;
 
@@ -216,7 +217,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;
 
@@ -429,7 +430,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;
@@ -705,7 +706,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 b51ee8ffa..8052b9561 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;
 
@@ -96,7 +97,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 e12a352c4..448c4073b 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 31125d93c..b5fa5cf19 100644
--- a/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
+++ b/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
@@ -587,7 +587,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);
     }
 
@@ -734,7 +734,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);
diff --git a/src/test/java/io/lettuce/core/support/CommonsPool2ConfigConverterUnitTests.java b/src/test/java/io/lettuce/core/support/CommonsPool2ConfigConverterUnitTests.java
index 82772e35c..7e6fea08f 100644
--- a/src/test/java/io/lettuce/core/support/CommonsPool2ConfigConverterUnitTests.java
+++ b/src/test/java/io/lettuce/core/support/CommonsPool2ConfigConverterUnitTests.java
@@ -19,22 +19,27 @@ import org.junit.jupiter.api.Test;
 @Tag(UNIT_TEST)
 class CommonsPool2ConfigConverterUnitTests {
 
+    private static final int MIN_IDLE_EXPECTED = 2;
+
+    private static final int MAX_IDLE_EXPECTED = 12;
+
+    private static final int MAX_TOTAL_EXPECTED = 13;
+
     @Test
     void shouldAdaptConfiguration() {
-
         GenericObjectPoolConfig<String> config = new GenericObjectPoolConfig<>();
-        config.setMinIdle(2);
-        config.setMaxIdle(12);
-        config.setMaxTotal(13);
+        config.setMinIdle(MIN_IDLE_EXPECTED);
+        config.setMaxIdle(MAX_IDLE_EXPECTED);
+        config.setMaxTotal(MAX_TOTAL_EXPECTED);
         config.setTestOnBorrow(true);
         config.setTestOnReturn(true);
         config.setTestOnCreate(true);
 
         BoundedPoolConfig result = CommonsPool2ConfigConverter.bounded(config);
 
-        assertThat(result.getMinIdle()).isEqualTo(2);
-        assertThat(result.getMaxIdle()).isEqualTo(12);
-        assertThat(result.getMaxTotal()).isEqualTo(13);
+        assertThat(result.getMinIdle()).isEqualTo(MIN_IDLE_EXPECTED);
+        assertThat(result.getMaxIdle()).isEqualTo(MAX_IDLE_EXPECTED);
+        assertThat(result.getMaxTotal()).isEqualTo(MAX_TOTAL_EXPECTED);
         assertThat(result.isTestOnAcquire()).isTrue();
         assertThat(result.isTestOnCreate()).isTrue();
         assertThat(result.isTestOnRelease()).isTrue();
diff --git a/src/test/java/io/redis/examples/async/StringExample.java b/src/test/java/io/redis/examples/async/StringExample.java
index 9be29395b..af856743e 100644
--- a/src/test/java/io/redis/examples/async/StringExample.java
+++ b/src/test/java/io/redis/examples/async/StringExample.java
@@ -7,15 +7,12 @@ import io.lettuce.core.api.StatefulRedisConnection;
 
 // REMOVE_START
 import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
 // REMOVE_END
 
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 
-// REMOVE_START
-import static org.assertj.core.api.Assertions.assertThat;
-// REMOVE_END
-
 public class StringExample {
 
     // REMOVE_START
@@ -29,7 +26,7 @@ public class StringExample {
 
             // STEP_START set_get
             CompletableFuture<Void> setAndGet = asyncCommands.set("bike:1", "Deimos").thenCompose(v -> {
-                System.out.println(v); // OK
+                System.out.println(v); // >>> OK
                 // REMOVE_START
                 assertThat(v).isEqualTo("OK");
                 // REMOVE_END
@@ -41,13 +38,16 @@ public class StringExample {
                         return res;
                     })
                     // REMOVE_END
-                    .thenAccept(System.out::println) // Deimos
+                    .thenAccept(System.out::println) // >>> Deimos
                     .toCompletableFuture();
             // STEP_END
+            // HIDE_START
+            setAndGet.join();
+            // HIDE_END
 
             // STEP_START setnx_xx
             CompletableFuture<Void> setnx = asyncCommands.setnx("bike:1", "bike").thenCompose(v -> {
-                System.out.println(v); // false (because key already exists)
+                System.out.println(v); // >>> false (because key already exists)
                 // REMOVE_START
                 assertThat(v).isFalse();
                 // REMOVE_END
@@ -59,8 +59,11 @@ public class StringExample {
                         return res;
                     })
                     // REMOVE_END
-                    .thenAccept(System.out::println) // Deimos (value is unchanged)
+                    .thenAccept(System.out::println) // >>> Deimos (value is unchanged)
                     .toCompletableFuture();
+            // HIDE_START
+            setnx.join();
+            // HIDE_END
 
             // set the value to "bike" if it already exists
             CompletableFuture<Void> setxx = asyncCommands.set("bike:1", "bike", SetArgs.Builder.xx())
@@ -70,8 +73,11 @@ public class StringExample {
                         return res;
                     })
                     // REMOVE_END
-                    .thenAccept(System.out::println) // OK
+                    .thenAccept(System.out::println) // >>> OK
                     .toCompletableFuture();
+            // HIDE_START
+            setxx.join();
+            // HIDE_END
             // STEP_END
 
             // STEP_START mset
@@ -81,7 +87,7 @@ public class StringExample {
             bikeMap.put("bike:3", "Vanth");
 
             CompletableFuture<Void> mset = asyncCommands.mset(bikeMap).thenCompose(v -> {
-                System.out.println(v); // OK
+                System.out.println(v); // >>> OK
                 return asyncCommands.mget("bike:1", "bike:2", "bike:3");
             })
                     // REMOVE_START
@@ -93,15 +99,19 @@ public class StringExample {
                         return res;
                     })
                     // REMOVE_END
-                    .thenAccept(System.out::println) // [KeyValue[bike:1, Deimos], KeyValue[bike:2, Ares], KeyValue[bike:3,
-                                                     // Vanth]]
+                    .thenAccept(System.out::println)
+                    // >>> [KeyValue[bike:1, Deimos], KeyValue[bike:2, Ares], KeyValue[bike:3,
+                    // Vanth]]
                     .toCompletableFuture();
             // STEP_END
+            // HIDE_START
+            mset.join();
+            // HIDE_END
 
             // STEP_START incr
             CompletableFuture<Void> incrby = asyncCommands.set("total_crashes", "0")
                     .thenCompose(v -> asyncCommands.incr("total_crashes")).thenCompose(v -> {
-                        System.out.println(v); // 1
+                        System.out.println(v); // >>> 1
                         // REMOVE_START
                         assertThat(v).isEqualTo(1L);
                         // REMOVE_END
@@ -113,12 +123,12 @@ public class StringExample {
                         return res;
                     })
                     // REMOVE_END
-                    .thenAccept(System.out::println) // 11
+                    .thenAccept(System.out::println) // >>> 11
                     .toCompletableFuture();
             // STEP_END
-
-            CompletableFuture.allOf(setAndGet, setnx, setxx, mset, incrby).join();
-
+            // HIDE_START
+            incrby.join();
+            // HIDE_END
         } finally {
             redisClient.shutdown();
         }
diff --git a/src/test/resources/docker/docker-compose.yml b/src/test/resources/docker/docker-compose.yml
index 2cc05fa3d..58a83da33 100644
--- a/src/test/resources/docker/docker-compose.yml
+++ b/src/test/resources/docker/docker-compose.yml
@@ -1,6 +1,6 @@
 ---
 x-client-libs-stack-image: &client-libs-stack-image
-    image: "redislabs/client-libs-test:${REDIS_STACK_VERSION:-8.0-M02}"
+    image: "redislabs/client-libs-test:${REDIS_STACK_VERSION:-8.0-M04-pre}"
 
 services: