diff --git a/pom.xml b/pom.xml
index 0e3024e099..541e10043a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-redis
- 4.0.0-SNAPSHOT
+ 4.0.0-GH-3223-SNAPSHOT
Spring Data Redis
Spring Data module for Redis
diff --git a/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java
index 5ce81a5ee7..bb95e48bad 100644
--- a/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java
@@ -38,6 +38,7 @@
* @author Christoph Strobl
* @author Jiahe Cai
* @author Ehsan Alemzadeh
+ * @author Chris Bono
*/
class DefaultValueOperations extends AbstractOperations implements ValueOperations {
@@ -46,37 +47,33 @@ class DefaultValueOperations extends AbstractOperations implements V
}
@Override
- public V get(Object key) {
+ public @Nullable V get(Object key) {
return execute(valueCallbackFor(key, DefaultedRedisConnection::get));
}
- @Nullable
@Override
- public V getAndDelete(K key) {
+ public @Nullable V getAndDelete(K key) {
return execute(valueCallbackFor(key, DefaultedRedisConnection::getDel));
}
- @Nullable
@Override
- public V getAndExpire(K key, long timeout, TimeUnit unit) {
+ public @Nullable V getAndExpire(K key, long timeout, TimeUnit unit) {
return execute(
valueCallbackFor(key, (connection, rawKey) -> connection.getEx(rawKey, Expiration.from(timeout, unit))));
}
- @Nullable
@Override
- public V getAndExpire(K key, Duration timeout) {
+ public @Nullable V getAndExpire(K key, Duration timeout) {
return execute(valueCallbackFor(key, (connection, rawKey) -> connection.getEx(rawKey, Expiration.from(timeout))));
}
- @Nullable
@Override
- public V getAndPersist(K key) {
+ public @Nullable V getAndPersist(K key) {
return execute(valueCallbackFor(key, (connection, rawKey) -> connection.getEx(rawKey, Expiration.persistent())));
}
@Override
- public V getAndSet(K key, V newValue) {
+ public @Nullable V getAndSet(K key, V newValue) {
byte[] rawValue = rawValue(newValue);
return execute(valueCallbackFor(key, (connection, rawKey) -> connection.getSet(rawKey, rawValue)));
@@ -139,7 +136,7 @@ public String get(K key, long start, long end) {
}
@Override
- public List multiGet(Collection keys) {
+ public List<@Nullable V> multiGet(Collection keys) {
if (keys.isEmpty()) {
return Collections.emptyList();
@@ -212,16 +209,16 @@ public void set(K key, V value, long timeout, TimeUnit unit) {
}
@Override
- public V setGet(K key, V value, long timeout, TimeUnit unit) {
+ public @Nullable V setGet(K key, V value, long timeout, TimeUnit unit) {
return doSetGet(key, value, Expiration.from(timeout, unit));
}
@Override
- public V setGet(K key, V value, Duration duration) {
+ public @Nullable V setGet(K key, V value, Duration duration) {
return doSetGet(key, value, Expiration.from(duration));
}
- private V doSetGet(K key, V value, Expiration duration) {
+ private @Nullable V doSetGet(K key, V value, Expiration duration) {
byte[] rawValue = rawValue(value);
return execute(new ValueDeserializingRedisCallback(key) {
diff --git a/src/main/java/org/springframework/data/redis/core/ValueOperations.java b/src/main/java/org/springframework/data/redis/core/ValueOperations.java
index 0c33203ba3..183a64fcb9 100644
--- a/src/main/java/org/springframework/data/redis/core/ValueOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/ValueOperations.java
@@ -23,6 +23,7 @@
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
+import org.jspecify.annotations.Nullable;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.util.Assert;
@@ -34,6 +35,7 @@
* @author Mark Paluch
* @author Jiahe Cai
* @author Marcin Grzejszczak
+ * @author Chris Bono
*/
@NullUnmarked
public interface ValueOperations {
@@ -60,7 +62,7 @@ public interface ValueOperations {
* @see Redis Documentation: SET
* @since 3.5
*/
- V setGet(@NonNull K key, @NonNull V value, long timeout, @NonNull TimeUnit unit);
+ @Nullable V setGet(@NonNull K key, @NonNull V value, long timeout, @NonNull TimeUnit unit);
/**
* Set the {@code value} and expiration {@code timeout} for {@code key}. Return the old string stored at key, or
@@ -74,7 +76,7 @@ public interface ValueOperations {
* @see Redis Documentation: SET
* @since 3.5
*/
- V setGet(@NonNull K key, @NonNull V value, @NonNull Duration duration);
+ @Nullable V setGet(@NonNull K key, @NonNull V value, @NonNull Duration duration);
/**
* Set the {@code value} and expiration {@code timeout} for {@code key}.
@@ -226,7 +228,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @return {@literal null} when key does not exist or used in pipeline / transaction.
* @see Redis Documentation: GET
*/
- V get(Object key);
+ @Nullable V get(Object key);
/**
* Return the value at {@code key} and delete the key.
@@ -236,7 +238,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see Redis Documentation: GETDEL
* @since 2.6
*/
- V getAndDelete(@NonNull K key);
+ @Nullable V getAndDelete(@NonNull K key);
/**
* Return the value at {@code key} and expire the key by applying {@code timeout}.
@@ -248,7 +250,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see Redis Documentation: GETEX
* @since 2.6
*/
- V getAndExpire(@NonNull K key, long timeout, @NonNull TimeUnit unit);
+ @Nullable V getAndExpire(@NonNull K key, long timeout, @NonNull TimeUnit unit);
/**
* Return the value at {@code key} and expire the key by applying {@code timeout}.
@@ -259,7 +261,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see Redis Documentation: GETEX
* @since 2.6
*/
- V getAndExpire(@NonNull K key, @NonNull Duration timeout);
+ @Nullable V getAndExpire(@NonNull K key, @NonNull Duration timeout);
/**
* Return the value at {@code key} and persist the key. This operation removes any TTL that is associated with
@@ -270,7 +272,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see Redis Documentation: GETEX
* @since 2.6
*/
- V getAndPersist(@NonNull K key);
+ @Nullable V getAndPersist(@NonNull K key);
/**
* Set {@code value} of {@code key} and return its old value.
@@ -279,7 +281,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @return {@literal null} when key does not exist or used in pipeline / transaction.
* @see Redis Documentation: GETSET
*/
- V getAndSet(@NonNull K key, @NonNull V value);
+ @Nullable V getAndSet(@NonNull K key, @NonNull V value);
/**
* Get multiple {@code keys}. Values are in the order of the requested keys Absent field values are represented using
@@ -289,7 +291,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @return {@literal null} when used in pipeline / transaction.
* @see Redis Documentation: MGET
*/
- List multiGet(@NonNull Collection<@NonNull K> keys);
+ List<@Nullable V> multiGet(@NonNull Collection<@NonNull K> keys);
/**
* Increment an integer value stored as string value under {@code key} by one.
diff --git a/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java
index 51b5b52643..316e29d68c 100644
--- a/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java
+++ b/src/test/java/org/springframework/data/redis/core/DefaultValueOperationsIntegrationTests.java
@@ -46,6 +46,7 @@
* @author Jiahe Cai
* @author Mark Paluch
* @author Hendrik Duerkop
+ * @author Chris Bono
*/
@ParameterizedClass
@MethodSource("testParams")
@@ -153,6 +154,21 @@ void testDecrementByLong() {
assertThat(valueOps.get(key)).isEqualTo((Long) value - 5);
}
+ @Test
+ void testMultiGet() {
+
+ K key1 = keyFactory.instance();
+ K key2 = keyFactory.instance();
+ K noSuchKey = keyFactory.instance();
+ V value1 = valueFactory.instance();
+ V value2 = valueFactory.instance();
+
+ valueOps.set(key1, value1);
+ valueOps.set(key2, value2);
+
+ assertThat(valueOps.multiGet(Arrays.asList(key1, noSuchKey, key2))).containsExactly(value1, null, value2);
+ }
+
@Test
void testMultiSetIfAbsent() {
@@ -213,6 +229,9 @@ void testGetSet() {
valueOps.set(key, value);
assertThat(valueOps.get(key)).isEqualTo(value);
+
+ K noSuchKey = keyFactory.instance();
+ assertThat(valueOps.get(noSuchKey)).isNull();
}
@Test // GH-2050
@@ -227,6 +246,9 @@ void testGetAndExpire() {
assertThat(valueOps.getAndExpire(key, Duration.ofSeconds(10))).isEqualTo(value1);
assertThat(redisTemplate.getExpire(key)).isGreaterThan(1);
+
+ K noSuchKey = keyFactory.instance();
+ assertThat(valueOps.getAndExpire(noSuchKey, Duration.ofSeconds(10))).isNull();
}
@Test // GH-2050
@@ -240,6 +262,9 @@ void testGetAndPersist() {
assertThat(valueOps.getAndPersist(key)).isEqualTo(value1);
assertThat(redisTemplate.getExpire(key)).isEqualTo(-1);
+
+ K noSuchKey = keyFactory.instance();
+ assertThat(valueOps.getAndPersist(noSuchKey)).isNull();
}
@Test // GH-2050
@@ -253,6 +278,9 @@ void testGetAndDelete() {
assertThat(valueOps.getAndDelete(key)).isEqualTo(value1);
assertThat(redisTemplate.hasKey(key)).isFalse();
+
+ K noSuchKey = keyFactory.instance();
+ assertThat(valueOps.getAndDelete(noSuchKey)).isNull();
}
@Test
@@ -265,6 +293,9 @@ void testGetAndSet() {
valueOps.set(key, value1);
assertThat(valueOps.getAndSet(key, value2)).isEqualTo(value1);
+
+ K noSuchKey = keyFactory.instance();
+ assertThat(valueOps.getAndSet(noSuchKey, value2)).isNull();
}
@Test
@@ -330,6 +361,9 @@ void testSetGetWithExpiration() {
assertThat(valueOps.setGet(key, value2, 1, TimeUnit.SECONDS)).isEqualTo(value1);
assertThat(valueOps.get(key)).isEqualTo(value2);
+
+ K noSuchKey = keyFactory.instance();
+ assertThat(valueOps.setGet(noSuchKey, value2, 1, TimeUnit.SECONDS)).isNull();
}
@Test
@@ -343,6 +377,9 @@ void testSetGetWithExpirationDuration() {
assertThat(valueOps.setGet(key, value2, Duration.ofMillis(1000))).isEqualTo(value1);
assertThat(valueOps.get(key)).isEqualTo(value2);
+
+ K noSuchKey = keyFactory.instance();
+ assertThat(valueOps.setGet(noSuchKey, value2, Duration.ofMillis(1000))).isNull();
}
@Test