From c56760b232959836f970ccb5f2a3f805f2f4549a Mon Sep 17 00:00:00 2001 From: Mingyuan Wu Date: Mon, 27 Oct 2025 23:39:22 +0800 Subject: [PATCH] Upgrade to Lettuce 7.0.0 Signed-off-by: Mingyuan Wu --- pom.xml | 2 +- .../lettuce/LettuceClusterKeyCommands.java | 3 +- .../connection/lettuce/LettuceConverters.java | 39 +++++++++++++++---- .../lettuce/LettuceKeyCommands.java | 3 +- .../LettuceReactiveClusterKeyCommands.java | 3 +- .../lettuce/LettuceReactiveKeyCommands.java | 3 +- .../LettuceClusterConnectionUnitTests.java | 9 +++-- .../LettuceConnectionFactoryUnitTests.java | 33 ++++++++++++---- .../lettuce/LettuceConvertersUnitTests.java | 35 ++++++++++++----- 9 files changed, 95 insertions(+), 35 deletions(-) diff --git a/pom.xml b/pom.xml index 0e3024e099..767046cd76 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 1.11.0 1.4.21 2.11.1 - 6.8.1.RELEASE + 7.0.0.RELEASE 7.0.0 1.01 4.2.3.Final diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java index 93a843a7f5..7edcef26a9 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java @@ -37,6 +37,7 @@ /** * @author Christoph Strobl * @author Mark Paluch + * @author Mingyuan Wu * @since 2.0 */ @NullUnmarked @@ -108,7 +109,7 @@ public Boolean move(byte @NonNull [] key, int dbIndex) { Assert.notNull(pattern, "Pattern must not be null"); return LettuceConverters.toBytesSet(connection.getClusterCommandExecutor() - .executeCommandOnSingleNode((LettuceClusterCommandCallback>) client -> client.keys(pattern), node) + .executeCommandOnSingleNode((LettuceClusterCommandCallback>) client -> client.keysLegacy(pattern), node) .getValue()); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index cfdda03683..3aaa1ab31e 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -19,6 +19,7 @@ import static org.springframework.data.redis.domain.geo.GeoReference.*; import io.lettuce.core.*; +import io.lettuce.core.RedisCredentialsProvider.ImmediateRedisCredentialsProvider; import io.lettuce.core.cluster.models.partitions.Partitions; import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag; @@ -87,6 +88,7 @@ * @author Vikas Garg * @author John Blum * @author Roman Osadchuk + * @author Mingyuan Wu */ @SuppressWarnings("ConstantConditions") public abstract class LettuceConverters extends Converters { @@ -452,8 +454,9 @@ static RedisSentinelConfiguration createRedisSentinelConfiguration(RedisURI redi RedisNode sentinelNode = new RedisNode(sentinelNodeRedisUri.getHost(), sentinelNodeRedisUri.getPort()); - if (sentinelNodeRedisUri.getPassword() != null) { - sentinelConfiguration.setSentinelPassword(sentinelNodeRedisUri.getPassword()); + RedisCredentials credential; + if( (credential = getRedisCredential(redisURI)) != null && credential.getPassword() != null) { + sentinelConfiguration.setSentinelPassword(credential.getPassword()); } sentinelConfiguration.addSentinel(sentinelNode); @@ -466,15 +469,35 @@ static RedisSentinelConfiguration createRedisSentinelConfiguration(RedisURI redi private static void applyAuthentication(RedisURI redisURI, RedisConfiguration.WithAuthentication redisConfiguration) { - if (StringUtils.hasText(redisURI.getUsername())) { - redisConfiguration.setUsername(redisURI.getUsername()); - } + RedisCredentials credential; + if( (credential = getRedisCredential(redisURI)) != null) { + if (StringUtils.hasText(credential.getUsername())) { + redisConfiguration.setUsername(credential.getUsername()); + } - if (redisURI.getPassword() != null) { - redisConfiguration.setPassword(redisURI.getPassword()); - } + if (credential.getPassword() != null) { + redisConfiguration.setPassword(credential.getPassword()); + } + } } + public static RedisCredentials getRedisCredential(RedisURI redisURI) { + + if (redisURI != null) { + RedisCredentialsProvider credentialsProvider = redisURI.getCredentialsProvider(); + if (credentialsProvider != null) { + RedisCredentials credential; + if(credentialsProvider instanceof ImmediateRedisCredentialsProvider immediateCredentialsProvider) { + credential = immediateCredentialsProvider.resolveCredentialsNow(); + }else { + credential = credentialsProvider.resolveCredentials().block(); + } + return credential; + } + } + return null; + } + @Contract("null -> null;!null -> !null") public static byte @Nullable [] toBytes(@Nullable String source) { return source != null ? source.getBytes() : null; diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java index 6228c9485a..861bc85e60 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java @@ -50,6 +50,7 @@ * @author Christoph Strobl * @author Mark Paluch * @author ihaohong + * @author Mingyuan Wu * @since 2.0 */ @NullUnmarked @@ -126,7 +127,7 @@ public Long touch(byte @NonNull [] @NonNull... keys) { Assert.notNull(pattern, "Pattern must not be null"); - return connection.invoke().fromMany(RedisKeyAsyncCommands::keys, pattern).toSet(); + return connection.invoke().fromMany(RedisKeyAsyncCommands::keysLegacy, pattern).toSet(); } /** diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterKeyCommands.java index 6d86fb9e46..423f46e45f 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterKeyCommands.java @@ -37,6 +37,7 @@ /** * @author Christoph Strobl * @author Mark Paluch + * @author Mingyuan Wu * @since 2.0 */ class LettuceReactiveClusterKeyCommands extends LettuceReactiveKeyCommands implements ReactiveClusterKeyCommands { @@ -62,7 +63,7 @@ public Mono> keys(RedisClusterNode node, ByteBuffer pattern) { Assert.notNull(pattern, "Pattern must not be null"); - return cmd.keys(pattern).collectList(); + return cmd.keysLegacy(pattern).collectList(); }).next(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java index 9913a9b07a..b863d229c8 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java @@ -48,6 +48,7 @@ * @author Christoph Strobl * @author Mark Paluch * @author Dahye Anne Lee + * @author Mingyuan Wu * @since 2.0 */ class LettuceReactiveKeyCommands implements ReactiveKeyCommands { @@ -125,7 +126,7 @@ public Flux> keys(Publisher new MultiValueResponse<>(pattern, value)); + return cmd.keysLegacy(pattern).collectList().map(value -> new MultiValueResponse<>(pattern, value)); })); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java index 7d2a1003bf..e6ea053063 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java @@ -55,6 +55,7 @@ /** * @author Christoph Strobl * @author Mark Paluch + * @author Mingyuan Wu */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @@ -196,15 +197,15 @@ void isClosedShouldReturnConnectionStateCorrectly() { @Test // DATAREDIS-315 void keysShouldOnlyBeRunOnDedicatedNodeWhenPinned() { - when(clusterConnection2Mock.keys(any(byte[].class))).thenReturn(Collections. emptyList()); + when(clusterConnection2Mock.keysLegacy(any(byte[].class))).thenReturn(Collections. emptyList()); byte[] pattern = LettuceConverters.toBytes("*"); connection.keys(CLUSTER_NODE_2, pattern); - verify(clusterConnection1Mock, never()).keys(pattern); - verify(clusterConnection2Mock, times(1)).keys(pattern); - verify(clusterConnection3Mock, never()).keys(pattern); + verify(clusterConnection1Mock, never()).keysLegacy(pattern); + verify(clusterConnection2Mock, times(1)).keysLegacy(pattern); + verify(clusterConnection3Mock, never()).keysLegacy(pattern); } @Test // DATAREDIS-315 diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java index 8fd3f0c747..9c503ee395 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java @@ -21,9 +21,11 @@ import static org.springframework.data.redis.connection.RedisConfiguration.*; import static org.springframework.data.redis.test.extension.LettuceTestClientResources.*; import static org.springframework.test.util.ReflectionTestUtils.*; +import static org.springframework.data.redis.connection.lettuce.LettuceConverters.getRedisCredential; import io.lettuce.core.AbstractRedisClient; import io.lettuce.core.ClientOptions; +import io.lettuce.core.RedisCredentials; import io.lettuce.core.RedisClient; import io.lettuce.core.RedisURI; import io.lettuce.core.SslVerifyMode; @@ -78,6 +80,7 @@ * @author Chris Bono * @author John Blum * @author Zhian Chen + * @author Mingyuan Wu */ class LettuceConnectionFactoryUnitTests { @@ -186,7 +189,9 @@ void passwordShouldBeSetCorrectlyOnClusterClient() { Iterable initialUris = (Iterable) getField(client, "initialUris"); for (RedisURI uri : initialUris) { - assertThat(uri.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray()); + RedisCredentials credential = getRedisCredential(uri); + assertThat(credential).isNotNull(); + assertThat(credential.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray()); } } @@ -257,10 +262,14 @@ void passwordShouldNotBeSetOnSentinelClient() { RedisURI redisUri = (RedisURI) getField(client, "redisURI"); - assertThat(redisUri.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray()); + RedisCredentials credential = getRedisCredential(redisUri); + assertThat(credential).isNotNull(); + assertThat(credential.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray()); for (RedisURI sentinel : redisUri.getSentinels()) { - assertThat(sentinel.getPassword()).isNull(); + RedisCredentials sentinelCredential = getRedisCredential(sentinel); + assertThat(sentinelCredential).isNotNull(); + assertThat(sentinelCredential.getPassword()).isNull(); } } @@ -281,10 +290,14 @@ void sentinelPasswordShouldBeSetOnSentinelClient() { RedisURI redisUri = (RedisURI) getField(client, "redisURI"); - assertThat(redisUri.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray()); + RedisCredentials credential = getRedisCredential(redisUri); + assertThat(credential).isNotNull(); + assertThat(credential.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray()); for (RedisURI sentinel : redisUri.getSentinels()) { - assertThat(sentinel.getPassword()).isEqualTo("sentinel-pwd".toCharArray()); + RedisCredentials sentinelCredentials = getRedisCredential(sentinel); + assertThat(sentinelCredentials).isNotNull(); + assertThat(sentinelCredentials.getPassword()).isEqualTo("sentinel-pwd".toCharArray()); } } @@ -338,10 +351,14 @@ void sentinelPasswordShouldNotLeakIntoDataNodeClient() { RedisURI redisUri = (RedisURI) getField(client, "redisURI"); - assertThat(redisUri.getPassword()).isNull(); + RedisCredentials credential = getRedisCredential(redisUri); + assertThat(credential).isNotNull(); + assertThat(credential.getPassword()).isNull(); for (RedisURI sentinel : redisUri.getSentinels()) { - assertThat(sentinel.getPassword()).isEqualTo("sentinel-pwd".toCharArray()); + RedisCredentials sentinelCredentials = getRedisCredential(sentinel); + assertThat(sentinelCredentials).isNotNull(); + assertThat(sentinelCredentials.getPassword()).isEqualTo("sentinel-pwd".toCharArray()); } } @@ -1224,7 +1241,7 @@ void createFullRedisSentinelConfiguration() { .create("redis-sentinel://fooUser:fooPass@myserver1:111,myserver2:222/7?sentinelMasterId=5150"); // Set the passwords directly on the sentinels so that it gets picked up by converter char[] sentinelPass = "changeme".toCharArray(); - redisURI.getSentinels().forEach(sentinelRedisUri -> sentinelRedisUri.setPassword(sentinelPass)); + redisURI.getSentinels().forEach(sentinelRedisUri -> sentinelRedisUri.setAuthentication(sentinelPass)); RedisSentinelConfiguration expected = new RedisSentinelConfiguration(); expected.setMaster("5150"); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java index 9671797ae6..3447a0c058 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java @@ -19,9 +19,11 @@ import static org.springframework.data.redis.connection.ClusterTestVariables.*; import static org.springframework.data.redis.connection.lettuce.LettuceCommandArgsComparator.*; import static org.springframework.test.util.ReflectionTestUtils.*; +import static org.springframework.data.redis.connection.lettuce.LettuceConverters.getRedisCredential; import io.lettuce.core.GetExArgs; import io.lettuce.core.Limit; +import io.lettuce.core.RedisCredentials; import io.lettuce.core.RedisURI; import io.lettuce.core.SetArgs; import io.lettuce.core.cluster.models.partitions.Partitions; @@ -52,6 +54,7 @@ * * @author Christoph Strobl * @author Vikas Garg + * @author Mingyuan Wu */ class LettuceConvertersUnitTests { @@ -277,12 +280,16 @@ void sentinelConfigurationWithAuth() { RedisURI redisURI = LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration); - assertThat(redisURI.getUsername()).isEqualTo("app"); - assertThat(redisURI.getPassword()).isEqualTo(dataPassword.get()); + RedisCredentials credential = getRedisCredential(redisURI); + assertThat(credential).isNotNull(); + assertThat(credential.getUsername()).isEqualTo("app"); + assertThat(credential.getPassword()).isEqualTo(dataPassword.get()); redisURI.getSentinels().forEach(sentinel -> { - assertThat(sentinel.getUsername()).isEqualTo("admin"); - assertThat(sentinel.getPassword()).isEqualTo(sentinelPassword.get()); + RedisCredentials sentinelCredential = getRedisCredential(sentinel); + assertThat(sentinelCredential).isNotNull(); + assertThat(sentinelCredential.getUsername()).isEqualTo("admin"); + assertThat(sentinelCredential.getPassword()).isEqualTo(sentinelPassword.get()); }); } @@ -299,11 +306,15 @@ void sentinelConfigurationSetSentinelPasswordIfUsernameNotPresent() { RedisURI redisURI = LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration); - assertThat(redisURI.getUsername()).isEqualTo("app"); + RedisCredentials credential = getRedisCredential(redisURI); + assertThat(credential).isNotNull(); + assertThat(credential.getUsername()).isEqualTo("app"); redisURI.getSentinels().forEach(sentinel -> { - assertThat(sentinel.getUsername()).isNull(); - assertThat(sentinel.getPassword()).isNotNull(); + RedisCredentials sentinelCredential = getRedisCredential(sentinel); + assertThat(sentinelCredential).isNotNull(); + assertThat(sentinelCredential.getUsername()).isNull(); + assertThat(sentinelCredential.getPassword()).isNotNull(); }); } @@ -320,11 +331,15 @@ void sentinelConfigurationShouldNotSetSentinelAuthIfUsernameIsPresentWithNoPassw RedisURI redisURI = LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration); - assertThat(redisURI.getUsername()).isEqualTo("app"); + RedisCredentials credential = getRedisCredential(redisURI); + assertThat(credential).isNotNull(); + assertThat(credential.getUsername()).isEqualTo("app"); redisURI.getSentinels().forEach(sentinel -> { - assertThat(sentinel.getUsername()).isNull(); - assertThat(sentinel.getPassword()).isNull(); + RedisCredentials sentinelCredential = getRedisCredential(sentinel); + assertThat(sentinelCredential).isNotNull(); + assertThat(sentinelCredential.getUsername()).isNull(); + assertThat(sentinelCredential.getPassword()).isNull(); }); }