> entries = new ArrayList<>(it.size());
- it.forEach((k, v) -> entries.add(Converters.entryOf(k, v)));
+ return convertedMapEntryList;
- return entries;
});
}
diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisInvoker.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisInvoker.java
index 805efabe4b..ef1771969d 100644
--- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisInvoker.java
+++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisInvoker.java
@@ -17,7 +17,6 @@
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
-import redis.clients.jedis.Queable;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.commands.DatabasePipelineCommands;
@@ -47,7 +46,7 @@
* composing a functional pipeline to transform the result using a {@link Converter}.
*
* Usage example:
- *
+ *
*
* JedisInvoker invoker = …;
*
@@ -62,6 +61,7 @@
*
* @author Mark Paluch
* @author Christoph Strobl
+ * @author John Blum
* @since 2.5
*/
class JedisInvoker {
@@ -937,10 +937,7 @@ static class DefaultSingleInvocationSpec implements SingleInvocationSpec {
@Override
public T get(Converter converter) {
-
- Assert.notNull(converter, "Converter must not be null");
-
- return synchronizer.invoke(parentFunction, parentPipelineFunction, converter, () -> null);
+ return getOrElse(converter, () -> null);
}
@Nullable
@@ -959,6 +956,7 @@ static class DefaultManyInvocationSpec implements ManyInvocationSpec {
private final Function>> parentPipelineFunction;
private final Synchronizer synchronizer;
+ @SuppressWarnings({ "rawtypes", "unchecked" })
DefaultManyInvocationSpec(Function> parentFunction,
Function>> parentPipelineFunction,
Synchronizer synchronizer) {
@@ -969,6 +967,7 @@ static class DefaultManyInvocationSpec implements ManyInvocationSpec {
}
@Override
+ @SuppressWarnings("all")
public List toList(Converter converter) {
Assert.notNull(converter, "Converter must not be null");
@@ -981,15 +980,17 @@ public List toList(Converter converter) {
List result = new ArrayList<>(source.size());
- for (S s : source) {
- result.add(converter.convert(s));
+ for (S element : source) {
+ result.add(converter.convert(element));
}
return result;
+
}, Collections::emptyList);
}
@Override
+ @SuppressWarnings("all")
public Set toSet(Converter converter) {
Assert.notNull(converter, "Converter must not be null");
@@ -1002,11 +1003,12 @@ public Set toSet(Converter converter) {
Set result = new LinkedHashSet<>(source.size());
- for (S s : source) {
- result.add(converter.convert(s));
+ for (S element : source) {
+ result.add(converter.convert(element));
}
return result;
+
}, Collections::emptySet);
}
}
@@ -1020,6 +1022,7 @@ interface Synchronizer {
@Nullable
@SuppressWarnings({ "unchecked", "rawtypes" })
default T invoke(Function callFunction, Function> pipelineFunction) {
+
return (T) doInvoke((Function) callFunction, (Function) pipelineFunction, Converters.identityConverter(),
() -> null);
}
@@ -1046,15 +1049,13 @@ interface ResponseCommands extends PipelineBinaryCommands, DatabasePipelineComma
/**
* Create a proxy to invoke methods dynamically on {@link Pipeline} or {@link Transaction} as those share many
* commands that are not defined on a common super-type.
- *
- * @param pipelineOrTransaction
- * @return
*/
- static ResponseCommands createCommands(Queable pipelineOrTransaction) {
+ static ResponseCommands createCommands(Object pipelineOrTransaction) {
ProxyFactory proxyFactory = new ProxyFactory(pipelineOrTransaction);
+
proxyFactory.addInterface(ResponseCommands.class);
+
return (ResponseCommands) proxyFactory.getProxy(JedisInvoker.class.getClassLoader());
}
-
}
diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java
index 1aab87de0a..a19247a8d1 100644
--- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java
@@ -22,6 +22,7 @@
import redis.clients.jedis.params.ZParams;
import redis.clients.jedis.params.ZRangeParams;
import redis.clients.jedis.resps.ScanResult;
+import redis.clients.jedis.util.KeyValue;
import java.util.LinkedHashSet;
import java.util.List;
@@ -31,7 +32,6 @@
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.connection.zset.Aggregate;
-import org.springframework.data.redis.connection.zset.DefaultTuple;
import org.springframework.data.redis.connection.zset.Tuple;
import org.springframework.data.redis.connection.zset.Weights;
import org.springframework.data.redis.core.Cursor;
@@ -42,11 +42,14 @@
import org.springframework.util.Assert;
/**
+ * {@link RedisZSetCommands} implementation for Jedis.
+ *
* @author Christoph Strobl
* @author Clement Ong
* @author Mark Paluch
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
+ * @author John Blum
* @since 2.0
*/
class JedisZSetCommands implements RedisZSetCommands {
@@ -74,8 +77,10 @@ public Long zAdd(byte[] key, Set tuples, ZAddArgs args) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(tuples, "Tuples must not be null");
- return connection.invoke().just(Jedis::zadd, PipelineBinaryCommands::zadd, key, JedisConverters.toTupleMap(tuples),
- JedisConverters.toZAddParams(args));
+ Long count = connection.invoke().just(Jedis::zadd, PipelineBinaryCommands::zadd, key,
+ JedisConverters.toTupleMap(tuples), JedisConverters.toZAddParams(args));
+
+ return count != null ? count : 0L;
}
@Override
@@ -424,7 +429,7 @@ public Set zDiff(byte[]... sets) {
Assert.notNull(sets, "Sets must not be null");
- return connection.invoke().just(Jedis::zdiff, PipelineBinaryCommands::zdiff, sets);
+ return connection.invoke().fromMany(Jedis::zdiff, PipelineBinaryCommands::zdiff, sets).toSet();
}
@Override
@@ -450,7 +455,7 @@ public Set zInter(byte[]... sets) {
Assert.notNull(sets, "Sets must not be null");
- return connection.invoke().just(Jedis::zinter, PipelineBinaryCommands::zinter, new ZParams(), sets);
+ return connection.invoke().fromMany(Jedis::zinter, PipelineBinaryCommands::zinter, new ZParams(), sets).toSet();
}
@Override
@@ -504,7 +509,7 @@ public Set zUnion(byte[]... sets) {
Assert.notNull(sets, "Sets must not be null");
- return connection.invoke().just(Jedis::zunion, PipelineBinaryCommands::zunion, new ZParams(), sets);
+ return connection.invoke().fromMany(Jedis::zunion, PipelineBinaryCommands::zunion, new ZParams(), sets).toSet();
}
@Override
@@ -772,21 +777,8 @@ static ZRangeParams toZRangeParams(Protocol.Keyword by, byte[] min, byte[] max,
return zRangeParams;
}
- /**
- * Workaround for broken Jedis BZPOP signature.
- *
- * @param bytes
- * @return
- */
@Nullable
- @SuppressWarnings("unchecked")
- private static Tuple toTuple(List> bytes) {
-
- if (bytes.isEmpty()) {
- return null;
- }
-
- return new DefaultTuple((byte[]) bytes.get(1), Double.parseDouble(new String((byte[]) bytes.get(2))));
+ private static Tuple toTuple(@Nullable KeyValue, redis.clients.jedis.resps.Tuple> keyValue) {
+ return keyValue != null ? JedisConverters.toTuple(keyValue.getValue()) : null;
}
-
}
diff --git a/src/main/java/org/springframework/data/redis/connection/zset/DefaultTuple.java b/src/main/java/org/springframework/data/redis/connection/zset/DefaultTuple.java
index eb2c198e8e..3862985bb8 100644
--- a/src/main/java/org/springframework/data/redis/connection/zset/DefaultTuple.java
+++ b/src/main/java/org/springframework/data/redis/connection/zset/DefaultTuple.java
@@ -24,17 +24,20 @@
*
* @author Costin Leau
* @author Christoph Strobl
+ * @author John Blum
*/
public class DefaultTuple implements Tuple {
+ private static final Double ZERO = 0.0d;
+
private final Double score;
private final byte[] value;
/**
- * Constructs a new DefaultTuple
instance.
+ * Constructs a new {@link DefaultTuple}.
*
- * @param value
- * @param score
+ * @param value {@link byte[]} of the member's raw value.
+ * @param score {@link Double score} of the raw value used in sorting.
*/
public DefaultTuple(byte[] value, Double score) {
diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java
index 78ffeb756e..13621d31fc 100644
--- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java
@@ -2279,7 +2279,7 @@ public void zPopMinShouldWorkCorrectly() {
@EnabledOnCommand("BZPOPMIN")
public void bzPopMinShouldWorkCorrectly() {
- assertThat(clusterConnection.bZPopMin(KEY_1_BYTES, 10, TimeUnit.MILLISECONDS)).isNull();
+ assertThat(clusterConnection.zSetCommands().zCard(KEY_1_BYTES)).isZero();
nativeConnection.zadd(KEY_1_BYTES, 10D, VALUE_1_BYTES);
nativeConnection.zadd(KEY_1_BYTES, 20D, VALUE_2_BYTES);
@@ -2306,7 +2306,7 @@ public void zPopMaxShouldWorkCorrectly() {
@EnabledOnCommand("BZPOPMAX")
public void bzPopMaxShouldWorkCorrectly() {
- assertThat(clusterConnection.bZPopMax(KEY_1_BYTES, 10, TimeUnit.MILLISECONDS)).isNull();
+ assertThat(clusterConnection.zSetCommands().zCard(KEY_1_BYTES)).isZero();
nativeConnection.zadd(KEY_1_BYTES, 10D, VALUE_1_BYTES);
nativeConnection.zadd(KEY_1_BYTES, 20D, VALUE_2_BYTES);
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 2a39274473..7f61f9aea5 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
@@ -165,7 +165,7 @@ public void scanShouldKeepTheConnectionOpen() {
connection.scan(ScanOptions.NONE);
- verify(jedisSpy, never()).quit();
+ verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531, GH-2006
@@ -177,7 +177,7 @@ public void scanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException
Cursor cursor = connection.scan(ScanOptions.NONE);
cursor.close();
- verify(jedisSpy, times(1)).quit();
+ verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-531
@@ -188,7 +188,7 @@ public void sScanShouldKeepTheConnectionOpen() {
connection.sScan("foo".getBytes(), ScanOptions.NONE);
- verify(jedisSpy, never()).quit();
+ verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531
@@ -200,7 +200,7 @@ public void sScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException
Cursor cursor = connection.sScan("foo".getBytes(), ScanOptions.NONE);
cursor.close();
- verify(jedisSpy, times(1)).quit();
+ verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-531
@@ -211,7 +211,7 @@ public void zScanShouldKeepTheConnectionOpen() {
connection.zScan("foo".getBytes(), ScanOptions.NONE);
- verify(jedisSpy, never()).quit();
+ verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531
@@ -223,7 +223,7 @@ public void zScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException
Cursor cursor = connection.zScan("foo".getBytes(), ScanOptions.NONE);
cursor.close();
- verify(jedisSpy, times(1)).quit();
+ verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-531
@@ -234,7 +234,7 @@ public void hScanShouldKeepTheConnectionOpen() {
connection.hScan("foo".getBytes(), ScanOptions.NONE);
- verify(jedisSpy, never()).quit();
+ verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531
@@ -246,7 +246,7 @@ public void hScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException
Cursor> cursor = connection.hScan("foo".getBytes(), ScanOptions.NONE);
cursor.close();
- verify(jedisSpy, times(1)).quit();
+ verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-714
diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java
index eb37cf171d..7cbc1b6e92 100644
--- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java
+++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java
@@ -16,7 +16,15 @@
package org.springframework.data.redis.connection.jedis;
import static org.assertj.core.api.Assertions.*;
-
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import redis.clients.jedis.Protocol;
import redis.clients.jedis.params.GetExParams;
import redis.clients.jedis.params.SetParams;
@@ -35,12 +43,15 @@
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
+import org.springframework.lang.Nullable;
+import org.springframework.test.util.ReflectionTestUtils;
/**
* Unit tests for {@link JedisConverters}.
*
* @author Christoph Strobl
* @author Mark Paluch
+ * @author John Blum
*/
class JedisConvertersUnitTests {
@@ -212,15 +223,31 @@ void toSetCommandExPxOptionShouldReturnEXforMilliseconds() {
@Test // GH-2050
void convertsExpirationToSetPXAT() {
- assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS)))
- .extracting(SetParams::toString).isEqualTo(SetParams.setParams().pxAt(10).toString());
+ SetParams mockSetParams = mock(SetParams.class);
+
+ doReturn(mockSetParams).when(mockSetParams).pxAt(anyLong());
+
+ Expiration expiration = Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS);
+
+ assertThat(JedisConverters.toSetCommandExPxArgument(expiration, mockSetParams)).isNotNull();
+
+ verify(mockSetParams, times(1)).pxAt(eq(10L));
+ verifyNoMoreInteractions(mockSetParams);
}
@Test // GH-2050
void convertsExpirationToSetEXAT() {
- assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.unixTimestamp(1, TimeUnit.MINUTES)))
- .extracting(SetParams::toString).isEqualTo(SetParams.setParams().exAt(60).toString());
+ SetParams mockSetParams = mock(SetParams.class);
+
+ doReturn(mockSetParams).when(mockSetParams).exAt(anyLong());
+
+ Expiration expiration = Expiration.unixTimestamp(1, TimeUnit.MINUTES);
+
+ assertThat(JedisConverters.toSetCommandExPxArgument(expiration, mockSetParams)).isNotNull();
+
+ verify(mockSetParams, times(1)).exAt(eq(60L));
+ verifyNoMoreInteractions(mockSetParams);
}
@Test // DATAREDIS-316, DATAREDIS-749
@@ -241,43 +268,91 @@ void toSetCommandNxXxOptionShouldReturnEmptyArrayforUpsert() {
@Test // GH-2050
void convertsExpirationToGetExEX() {
- assertThat(JedisConverters.toGetExParams(Expiration.seconds(10))).extracting(GetExParams::toString)
- .isEqualTo(new GetExParams().ex(10).toString());
+ GetExParams mockGetExParams = mock(GetExParams.class);
+
+ doReturn(mockGetExParams).when(mockGetExParams).ex(anyLong());
+
+ Expiration expiration = Expiration.seconds(10);
+
+ assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
+
+ verify(mockGetExParams, times(1)).ex(eq(10L));
+ verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationWithTimeUnitToGetExEX() {
- assertThat(JedisConverters.toGetExParams(Expiration.from(1, TimeUnit.MINUTES))).extracting(GetExParams::toString)
- .isEqualTo(new GetExParams().ex(60).toString());
+ GetExParams mockGetExParams = mock(GetExParams.class);
+
+ doReturn(mockGetExParams).when(mockGetExParams).ex(anyLong());
+
+ Expiration expiration = Expiration.from(1, TimeUnit.MINUTES);
+
+ assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
+
+ verify(mockGetExParams, times(1)).ex(eq(60L)); // seconds
+ verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationToGetExPEX() {
- assertThat(JedisConverters.toGetExParams(Expiration.milliseconds(10))).extracting(GetExParams::toString)
- .isEqualTo(new GetExParams().px(10).toString());
+ GetExParams mockGetExParams = mock(GetExParams.class);
+
+ doReturn(mockGetExParams).when(mockGetExParams).px(anyLong());
+
+ Expiration expiration = Expiration.milliseconds(10L);
+
+ assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
+
+ verify(mockGetExParams, times(1)).px(eq(10L));
+ verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationToGetExEXAT() {
- assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(10, TimeUnit.SECONDS)))
- .extracting(GetExParams::toString).isEqualTo(new GetExParams().exAt(10).toString());
+ GetExParams mockGetExParams = mock(GetExParams.class);
+
+ doReturn(mockGetExParams).when(mockGetExParams).exAt(anyLong());
+
+ Expiration expiration = Expiration.unixTimestamp(10, TimeUnit.SECONDS);
+
+ assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
+
+ verify(mockGetExParams, times(1)).exAt(eq(10L));
+ verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationWithTimeUnitToGetExEXAT() {
- assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(1, TimeUnit.MINUTES)))
- .extracting(GetExParams::toString).isEqualTo(new GetExParams().exAt(60).toString());
+ GetExParams mockGetExParams = mock(GetExParams.class);
+
+ doReturn(mockGetExParams).when(mockGetExParams).exAt(anyLong());
+
+ Expiration expiration = Expiration.unixTimestamp(1, TimeUnit.MINUTES);
+
+ assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
+
+ verify(mockGetExParams, times(1)).exAt(eq(60L));
+ verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationToGetExPXAT() {
- assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS)))
- .extracting(GetExParams::toString).isEqualTo(new GetExParams().pxAt(10).toString());
+ GetExParams mockGetExParams = mock(GetExParams.class);
+
+ doReturn(mockGetExParams).when(mockGetExParams).pxAt(anyLong());
+
+ Expiration expiration = Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS);
+
+ assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
+
+ verify(mockGetExParams, times(1)).pxAt(eq(10L));
+ verifyNoMoreInteractions(mockGetExParams);
}
private void verifyRedisServerInfo(RedisServer server, Map values) {
@@ -289,18 +364,22 @@ private void verifyRedisServerInfo(RedisServer server, Map value
private static String toString(SetParams setParams) {
- StringBuilder builder = new StringBuilder();
+ StringBuilder stringBuilder = new StringBuilder();
- for (byte[] parameter : setParams.getByteParams()) {
+ stringBuilder.append(toString((Protocol.Keyword) ReflectionTestUtils.getField(setParams, "existance")));
+ stringBuilder.append(toString((Protocol.Keyword) ReflectionTestUtils.getField(setParams, "expiration")));
- if (builder.length() != 0) {
- builder.append(' ');
- }
+ Long expirationValue = (Long) ReflectionTestUtils.getField(setParams, "expirationValue");
- builder.append(new String(parameter));
+ if (expirationValue != null) {
+ stringBuilder.append(" ").append(expirationValue);
}
- return builder.toString();
+ return stringBuilder.toString().trim();
+ }
+
+ private static String toString(@Nullable Enum> value) {
+ return value != null ? value.name().toLowerCase() : "";
}
private Map getRedisServerInfoMap(String name, int port) {