From 9d212f84d84f4b1be047e19c557e07c626fc1ace Mon Sep 17 00:00:00 2001 From: Dongliang Xie Date: Wed, 24 Jun 2026 23:36:35 +0800 Subject: [PATCH] Align Jedis restore TTL parameter with long type. Signed-off-by: Dongliang Xie --- .../connection/jedis/JedisKeyCommands.java | 9 +-- .../jedis/JedisConnectionUnitTests.java | 78 +++++++++++++++---- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java index a7368a2af8..e0bd0cadae 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java @@ -62,6 +62,7 @@ * @author ihaohong * @author Yordan Tsintsov * @author Tihomir Mateev + * @author Dongliang Xie * @since 2.0 */ @NullUnmarked @@ -409,16 +410,12 @@ public void restore(byte @NonNull [] key, long ttlInMillis, byte @NonNull [] ser if (replace) { connection.invokeStatus().just(KeyBinaryCommands::restore, KeyPipelineBinaryCommands::restore, key, - (int) ttlInMillis, serializedValue, RestoreParams.restoreParams().replace()); + ttlInMillis, serializedValue, RestoreParams.restoreParams().replace()); return; } - if (ttlInMillis > Integer.MAX_VALUE) { - throw new IllegalArgumentException("TtlInMillis must be less than Integer.MAX_VALUE for restore in Jedis"); - } - connection.invokeStatus().just(KeyBinaryCommands::restore, KeyPipelineBinaryCommands::restore, key, - (int) ttlInMillis, serializedValue); + ttlInMillis, serializedValue); } @Override diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTests.java index 9654345f49..5af5ab9ca3 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTests.java @@ -18,9 +18,11 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import redis.clients.jedis.CommandArguments; import redis.clients.jedis.CommandObject; import redis.clients.jedis.Connection; import redis.clients.jedis.Jedis; +import redis.clients.jedis.args.Rawable; import java.io.IOException; @@ -28,7 +30,6 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.redis.connection.AbstractConnectionUnitTestBase; @@ -43,6 +44,7 @@ * * @author Christoph Strobl * @author Tihomir Mateev + * @author Dongliang Xie */ class JedisConnectionUnitTests { @@ -61,23 +63,51 @@ public void setUp() { } /** - * Captures the CommandObject sent via executeCommand and returns a string containing - * the command name and all arguments. + * Captures the command sent to the mock connection and returns a string containing the + * command name and all arguments. */ - @SuppressWarnings("unchecked") private String captureCommand() { - ArgumentCaptor> captor = ArgumentCaptor.forClass(CommandObject.class); - verify(connectionMock, atLeastOnce()).executeCommand(captor.capture()); - CommandObject lastCommand = captor.getValue(); - // Build a string from all raw arguments + + String command = null; + + for (var invocation : mockingDetails(connectionMock).getInvocations()) { + + Object[] arguments = invocation.getArguments(); + + if (arguments.length != 1) { + continue; + } + + if (arguments[0] instanceof CommandObject commandObject) { + command = commandToString(commandObject.getArguments()); + } else if (arguments[0] instanceof CommandArguments commandArguments) { + command = commandToString(commandArguments); + } + } + + assertThat(command).as("captured Redis command").isNotNull(); + return command; + } + + private String commandToString(Iterable arguments) { + StringBuilder sb = new StringBuilder(); - for (var arg : lastCommand.getArguments()) { - if (sb.length() > 0) sb.append(" "); + + for (Rawable arg : arguments) { + if (sb.length() > 0) { + sb.append(" "); + } sb.append(new String(arg.getRaw())); } + return sb.toString(); } + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void returnOkForCommands() { + when(connectionMock.executeCommand(any(CommandObject.class))).thenReturn("OK"); + } + @Test // DATAREDIS-184, GH-2153 void shutdownWithNullShouldDelegateCommandCorrectly() { @@ -166,10 +196,30 @@ void shouldThrowExceptionWhenAccessingRedisSentinelsCommandsWhenNoSentinelsConfi .isThrownBy(() -> connection.getSentinelConnection()); } - @Test // DATAREDIS-472 - void restoreShouldThrowExceptionWhenTtlInMillisExceedsIntegerRange() { - assertThatIllegalArgumentException() - .isThrownBy(() -> connection.restore("foo".getBytes(), (long) Integer.MAX_VALUE + 1L, "bar".getBytes())); + @Test // GH-3386 + void restoreShouldPassLongTtlToJedis() { + + long ttlInMillis = (long) Integer.MAX_VALUE + 1L; + + returnOkForCommands(); + + connection.restore("foo".getBytes(), ttlInMillis, "bar".getBytes()); + + String command = captureCommand(); + assertThat(command).contains("RESTORE").contains(Long.toString(ttlInMillis)); + } + + @Test // GH-3386 + void restoreWithReplaceShouldPassLongTtlToJedis() { + + long ttlInMillis = (long) Integer.MAX_VALUE + 1L; + + returnOkForCommands(); + + connection.restore("foo".getBytes(), ttlInMillis, "bar".getBytes(), true); + + String command = captureCommand(); + assertThat(command).contains("RESTORE").contains(Long.toString(ttlInMillis)).contains("REPLACE"); } @Test // DATAREDIS-472