Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3223-SNAPSHOT</version>

<name>Spring Data Redis</name>
<description>Spring Data module for Redis</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* @author Christoph Strobl
* @author Jiahe Cai
* @author Ehsan Alemzadeh
* @author Chris Bono
*/
class DefaultValueOperations<K, V> extends AbstractOperations<K, V> implements ValueOperations<K, V> {

Expand All @@ -46,37 +47,33 @@ class DefaultValueOperations<K, V> extends AbstractOperations<K, V> 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)));
Expand Down Expand Up @@ -139,7 +136,7 @@ public String get(K key, long start, long end) {
}

@Override
public List<V> multiGet(Collection<K> keys) {
public List<@Nullable V> multiGet(Collection<K> keys) {

if (keys.isEmpty()) {
return Collections.emptyList();
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -34,6 +35,7 @@
* @author Mark Paluch
* @author Jiahe Cai
* @author Marcin Grzejszczak
* @author Chris Bono
*/
@NullUnmarked
public interface ValueOperations<K, V> {
Expand All @@ -60,7 +62,7 @@ public interface ValueOperations<K, V> {
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
* @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
Expand All @@ -74,7 +76,7 @@ public interface ValueOperations<K, V> {
* @see <a href="https://redis.io/commands/set">Redis Documentation: SET</a>
* @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}.
Expand Down Expand Up @@ -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 <a href="https://redis.io/commands/get">Redis Documentation: GET</a>
*/
V get(Object key);
@Nullable V get(Object key);

/**
* Return the value at {@code key} and delete the key.
Expand All @@ -236,7 +238,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see <a href="https://redis.io/commands/getdel">Redis Documentation: GETDEL</a>
* @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}.
Expand All @@ -248,7 +250,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see <a href="https://redis.io/commands/getex">Redis Documentation: GETEX</a>
* @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}.
Expand All @@ -259,7 +261,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see <a href="https://redis.io/commands/getex">Redis Documentation: GETEX</a>
* @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
Expand All @@ -270,7 +272,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @see <a href="https://redis.io/commands/getex">Redis Documentation: GETEX</a>
* @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.
Expand All @@ -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 <a href="https://redis.io/commands/getset">Redis Documentation: GETSET</a>
*/
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
Expand All @@ -289,7 +291,7 @@ default Boolean setIfPresent(@NonNull K key, @NonNull V value, @NonNull Duration
* @return {@literal null} when used in pipeline / transaction.
* @see <a href="https://redis.io/commands/mget">Redis Documentation: MGET</a>
*/
List<V> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
* @author Jiahe Cai
* @author Mark Paluch
* @author Hendrik Duerkop
* @author Chris Bono
*/
@ParameterizedClass
@MethodSource("testParams")
Expand Down Expand Up @@ -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() {

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down