diff --git a/pom.xml b/pom.xml index 7a7d83cee6..202bcf88f0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-redis - 3.0.0-SNAPSHOT + 3.0.0-GH-2212-SNAPSHOT Spring Data Redis @@ -20,9 +20,9 @@ 4.0.2 1.9.4 1.4.19 - 2.9.0 + 2.11.1 6.1.8.RELEASE - 3.8.0 + 4.2.0 1.01 4.1.72.Final spring.data.redis diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 14db736982..e30c69588a 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -3,7 +3,12 @@ This section briefly covers items that are new and noteworthy in the latest releases. -[[new-in-2.7.0]] +[[new-in-3.0.0]] +== New in Spring Data Redis 3.0 + +* Upgrade to Jedis 4.1. Jedis 4 imposes certain limitations on transactions and pipelines and commands used in pipelines/transactions, see <>. + + == New in Spring Data Redis 2.7 * Sentinel ACL authentication considering a sentinel-specific username. Setting a username enables username and password authentication requiring Redis 6. diff --git a/src/main/asciidoc/reference/redis-cluster.adoc b/src/main/asciidoc/reference/redis-cluster.adoc index 8edf4d667e..55f4b02fdc 100644 --- a/src/main/asciidoc/reference/redis-cluster.adoc +++ b/src/main/asciidoc/reference/redis-cluster.adoc @@ -47,7 +47,7 @@ public class AppConfig { public @Bean RedisConnectionFactory connectionFactory() { - return new JedisConnectionFactory( + return new LettuceConnectionFactory( new RedisClusterConfiguration(clusterProperties.getNodes())); } } diff --git a/src/main/asciidoc/reference/redis-repositories.adoc b/src/main/asciidoc/reference/redis-repositories.adoc index 5aec8b0fbb..dcb801ee6e 100644 --- a/src/main/asciidoc/reference/redis-repositories.adoc +++ b/src/main/asciidoc/reference/redis-repositories.adoc @@ -58,7 +58,7 @@ public class ApplicationConfig { @Bean public RedisConnectionFactory connectionFactory() { - return new JedisConnectionFactory(); + return new LettuceConnectionFactory(); } @Bean @@ -843,10 +843,10 @@ class RedisOperationsProducer { @Produces RedisConnectionFactory redisConnectionFactory() { - JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(new RedisStandaloneConfiguration()); - jedisConnectionFactory.afterPropertiesSet(); + LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration()); + connectionFactory.afterPropertiesSet(); - return jedisConnectionFactory; + return connectionFactory; } void disposeRedisConnectionFactory(@Disposes RedisConnectionFactory redisConnectionFactory) throws Exception { diff --git a/src/main/asciidoc/reference/redis.adoc b/src/main/asciidoc/reference/redis.adoc index c0976e9062..8c9801b018 100644 --- a/src/main/asciidoc/reference/redis.adoc +++ b/src/main/asciidoc/reference/redis.adoc @@ -118,7 +118,7 @@ Unfortunately, currently, not all connectors support all Redis features. When in | Other Connection Features | Singleton-connection sharing for non-blocking commands -| `JedisShardInfo` support +| Pipelining and Transactions mutually exclusive. Cannot use server/connection commands in pipeline/transactions. | SSL Support | X @@ -130,11 +130,11 @@ Unfortunately, currently, not all connectors support all Redis features. When in | <> | X -| X +| X (Pipelining and Transactions mutually exclusive) | <> | X -| X +| X (Pipelining and Transactions mutually exclusive) | Datatype support | Key, String, List, Set, Sorted Set, Hash, Server, Stream, Scripting, Geo, HyperLogLog @@ -204,7 +204,7 @@ NOTE: Netty currently supports the epoll (Linux) and kqueue (BSD/macOS) interfac [[redis:connectors:jedis]] === Configuring the Jedis Connector -https://github.com/xetorthio/jedis[Jedis] is a community-driven connector supported by the Spring Data Redis module through the `org.springframework.data.redis.connection.jedis` package. +https://github.com/redis/jedis[Jedis] is a community-driven connector supported by the Spring Data Redis module through the `org.springframework.data.redis.connection.jedis` package. .Add the following to the pom.xml files `dependencies` element: @@ -223,7 +223,6 @@ https://github.com/xetorthio/jedis[Jedis] is a community-driven connector suppor ---- - In its simplest form, the Jedis configuration looks as follow: [source,java] @@ -288,27 +287,27 @@ For dealing with high-availability Redis, Spring Data Redis has support for http [source,java] ---- /** - * Jedis + * Lettuce */ @Bean -public RedisConnectionFactory jedisConnectionFactory() { +public RedisConnectionFactory lettuceConnectionFactory() { RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster") .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380); - return new JedisConnectionFactory(sentinelConfig); + return new LettuceConnectionFactory(sentinelConfig); } /** - * Lettuce + * Jedis */ @Bean -public RedisConnectionFactory lettuceConnectionFactory() { +public RedisConnectionFactory jedisConnectionFactory() { RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster") .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380); - return new LettuceConnectionFactory(sentinelConfig); + return new JedisConnectionFactory(sentinelConfig); } ---- @@ -400,9 +399,9 @@ For cases where you need a certain template view, declare the view as a dependen xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + - + ... @@ -439,9 +438,9 @@ Since it is quite common for the keys and values stored in Redis to be `java.lan xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + - + ... ---- diff --git a/src/main/java/org/springframework/data/redis/connection/convert/Converters.java b/src/main/java/org/springframework/data/redis/connection/convert/Converters.java index 10ac7fd7a7..7a8bb6449d 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/Converters.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/Converters.java @@ -58,9 +58,8 @@ * @author Mark Paluch * @author Christoph Strobl */ -abstract public class Converters { +public abstract class Converters { - // private static final Log LOGGER = LogFactory.getLog(Converters.class); private static final Log LOGGER = LogFactory.getLog(Converters.class); private static final byte[] ONE = new byte[] { '1' }; diff --git a/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java index d3e266e130..adb0646540 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.connection.convert; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; @@ -48,4 +49,8 @@ public Set convert(Set source) { return source.stream().map(itemConverter::convert).collect(Collectors.toCollection(LinkedHashSet::new)); } + public Set convert(Collection source) { + return source.stream().map(itemConverter::convert).collect(Collectors.toCollection(LinkedHashSet::new)); + } + } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientUtils.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientUtils.java index e90342a0ce..7675e67524 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientUtils.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientUtils.java @@ -15,23 +15,13 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.Builder; -import redis.clients.jedis.Client; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Protocol.Command; -import redis.clients.jedis.Queable; -import redis.clients.jedis.Response; -import redis.clients.jedis.util.SafeEncoder; +import redis.clients.jedis.Protocol; +import redis.clients.jedis.commands.ProtocolCommand; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collectors; -import org.springframework.util.ReflectionUtils; - /** * Utility class to dispatch arbitrary Redis commands using Jedis commands. * @@ -43,128 +33,23 @@ @SuppressWarnings({ "unchecked", "ConstantConditions" }) class JedisClientUtils { - private static final Method GET_RESPONSE; private static final Set KNOWN_COMMANDS; - private static final Builder OBJECT_BUILDER; static { - - GET_RESPONSE = ReflectionUtils.findMethod(Queable.class, "getResponse", Builder.class); - ReflectionUtils.makeAccessible(GET_RESPONSE); - - KNOWN_COMMANDS = Arrays.stream(Command.values()).map(Enum::name).collect(Collectors.toSet()); - - OBJECT_BUILDER = new Builder() { - public Object build(Object data) { - return data; - } - - public String toString() { - return "Object"; - } - }; - } - - /** - * Execute an arbitrary on the supplied {@link Jedis} instance. - * - * @param command the command. - * @param keys must not be {@literal null}, may be empty. - * @param args must not be {@literal null}, may be empty. - * @param jedis must not be {@literal null}. - * @return the response, can be be {@literal null}. - */ - static T execute(String command, byte[][] keys, byte[][] args, Supplier jedis) { - return execute(command, keys, args, jedis, it -> (T) it.getOne()); - } - - /** - * Execute an arbitrary on the supplied {@link Jedis} instance. - * - * @param command the command. - * @param keys must not be {@literal null}, may be empty. - * @param args must not be {@literal null}, may be empty. - * @param jedis must not be {@literal null}. - * @param responseMapper must not be {@literal null}. - * @return the response, can be be {@literal null}. - * @since 2.1 - */ - static T execute(String command, byte[][] keys, byte[][] args, Supplier jedis, - Function responseMapper) { - - byte[][] commandArgs = getCommandArguments(keys, args); - - Client client = sendCommand(command, commandArgs, jedis.get()); - - return responseMapper.apply(client); + KNOWN_COMMANDS = Arrays.stream(Protocol.Command.values()).map(Enum::name).collect(Collectors.toSet()); } - /** - * Send a Redis command and retrieve the {@link Client} for response retrieval. - * - * @param command the command. - * @param args must not be {@literal null}, may be empty. - * @param jedis must not be {@literal null}. - * @return the {@link Client} instance used to send the command. - */ - static Client sendCommand(String command, byte[][] args, Jedis jedis) { - - Client client = jedis.getClient(); - - sendCommand(client, command, args); - - return client; - } - - private static void sendCommand(Client client, String command, byte[][] args) { + public static ProtocolCommand getCommand(String command) { if (isKnownCommand(command)) { - client.sendCommand(Command.valueOf(command.trim().toUpperCase()), args); - } else { - client.sendCommand(() -> SafeEncoder.encode(command.trim().toUpperCase()), args); + return Protocol.Command.valueOf(command.trim().toUpperCase()); } + + return () -> JedisConverters.toBytes(command); } private static boolean isKnownCommand(String command) { return KNOWN_COMMANDS.contains(command); } - private static byte[][] getCommandArguments(byte[][] keys, byte[][] args) { - - if (keys.length == 0) { - return args; - } - - if (args.length == 0) { - return keys; - } - - byte[][] commandArgs = new byte[keys.length + args.length][]; - - System.arraycopy(keys, 0, commandArgs, 0, keys.length); - System.arraycopy(args, 0, commandArgs, keys.length, args.length); - - return commandArgs; - } - - /** - * @param jedis the client instance. - * @return {@literal true} if the connection has entered {@literal MULTI} state. - */ - static boolean isInMulti(Jedis jedis) { - return jedis.getClient().isInMulti(); - } - - /** - * Retrieve the {@link Response} object from a {@link redis.clients.jedis.Transaction} or a - * {@link redis.clients.jedis.Pipeline} for response synchronization. - * - * @param target a {@link redis.clients.jedis.Transaction} or {@link redis.clients.jedis.Pipeline}, must not be - * {@literal null}. - * @return the {@link Response} wrapper object. - */ - static Response getResponse(Object target) { - return (Response) ReflectionUtils.invokeMethod(GET_RESPONSE, target, OBJECT_BUILDER); - } - } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java index 6ffcf80c2e..6f02406d1f 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java @@ -15,13 +15,12 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.Client; +import redis.clients.jedis.Connection; +import redis.clients.jedis.ConnectionPool; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisClusterConnectionHandler; -import redis.clients.jedis.JedisPool; +import redis.clients.jedis.providers.ClusterConnectionProvider; import java.time.Duration; import java.util.ArrayList; @@ -33,7 +32,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -78,8 +76,6 @@ public class JedisClusterConnection implements RedisClusterConnection { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy( JedisExceptionConverter.INSTANCE); - private static final byte[][] EMPTY_2D_BYTE_ARRAY = new byte[0][]; - private final Log log = LogFactory.getLog(getClass()); private final JedisCluster cluster; @@ -97,7 +93,7 @@ public class JedisClusterConnection implements RedisClusterConnection { private boolean closed; private final ClusterTopologyProvider topologyProvider; - private ClusterCommandExecutor clusterCommandExecutor; + private final ClusterCommandExecutor clusterCommandExecutor; private final boolean disposeClusterCommandExecutorOnClose; private volatile @Nullable JedisSubscription subscription; @@ -120,8 +116,11 @@ public JedisClusterConnection(JedisCluster cluster) { disposeClusterCommandExecutorOnClose = true; try { - DirectFieldAccessor dfa = new DirectFieldAccessor(cluster); - clusterCommandExecutor.setMaxRedirects((Integer) dfa.getPropertyValue("maxRedirections")); + + DirectFieldAccessor executorDfa = new DirectFieldAccessor(cluster); + Object custerCommandExecutor = executorDfa.getPropertyValue("executor"); + DirectFieldAccessor dfa = new DirectFieldAccessor(custerCommandExecutor); + clusterCommandExecutor.setMaxRedirects((Integer) dfa.getPropertyValue("maxRedirects")); } catch (Exception e) { // ignore it and work with the executor default } @@ -168,20 +167,14 @@ public Object execute(String command, byte[]... args) { Assert.notNull(command, "Command must not be null!"); Assert.notNull(args, "Args must not be null!"); - return clusterCommandExecutor - .executeCommandOnArbitraryNode((JedisClusterCommandCallback) client -> JedisClientUtils.execute(command, - EMPTY_2D_BYTE_ARRAY, args, () -> client)) + return clusterCommandExecutor.executeCommandOnArbitraryNode( + (JedisClusterCommandCallback) client -> client.sendCommand(JedisClientUtils.getCommand(command), args)) .getValue(); } @Nullable @Override public T execute(String command, byte[] key, Collection args) { - return execute(command, key, args, it -> (T) it.getOne()); - } - - @Nullable - T execute(String command, byte[] key, Collection args, Function responseMapper) { Assert.notNull(command, "Command must not be null!"); Assert.notNull(key, "Key must not be null!"); @@ -191,8 +184,9 @@ T execute(String command, byte[] key, Collection args, Function) client -> JedisClientUtils - .execute(command, EMPTY_2D_BYTE_ARRAY, commandArgs, () -> client, responseMapper), keyMaster).getValue(); + return clusterCommandExecutor.executeCommandOnSingleNode((JedisClusterCommandCallback) client -> { + return (T) client.sendCommand(JedisClientUtils.getCommand(command), commandArgs); + }, keyMaster).getValue(); } private static byte[][] getCommandArguments(byte[] key, Collection args) { @@ -238,9 +232,9 @@ public List execute(String command, Collection keys, Collection) (client, key) -> { - return JedisClientUtils.execute(command, new byte[][] { key }, args.toArray(new byte[args.size()][]), - () -> client); + return (T) client.sendCommand(JedisClientUtils.getCommand(command), getCommandArguments(key, args)); }, keys).resultsAsList(); + } @Override @@ -409,18 +403,13 @@ public void select(int dbIndex) { @Override public byte[] echo(byte[] message) { - - try { - return cluster.echo(message); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + throw new InvalidDataAccessApiUsageException("Echo not supported in cluster mode."); } @Override public String ping() { - return !clusterCommandExecutor.executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::ping) + return !clusterCommandExecutor.executeCommandOnAllNodes((JedisClusterCommandCallback) Jedis::ping) .resultsAsList().isEmpty() ? "PONG" : null; } @@ -428,8 +417,8 @@ public String ping() { @Override public String ping(RedisClusterNode node) { - return clusterCommandExecutor - .executeCommandOnSingleNode((JedisClusterCommandCallback) BinaryJedis::ping, node).getValue(); + return clusterCommandExecutor.executeCommandOnSingleNode((JedisClusterCommandCallback) Jedis::ping, node) + .getValue(); } /* @@ -552,8 +541,10 @@ public void clusterReplicate(RedisClusterNode master, RedisClusterNode replica) @Override public Integer clusterGetSlotForKey(byte[] key) { - return clusterCommandExecutor.executeCommandOnArbitraryNode((JedisClusterCommandCallback) client -> client - .clusterKeySlot(JedisConverters.toString(key)).intValue()).getValue(); + return clusterCommandExecutor + .executeCommandOnArbitraryNode( + (JedisClusterCommandCallback) client -> (int) client.clusterKeySlot(JedisConverters.toString(key))) + .getValue(); } @Override @@ -662,17 +653,17 @@ public boolean isPipelined() { @Override public void openPipeline() { - throw new UnsupportedOperationException("Pipeline is currently not supported for JedisClusterConnection."); + throw new InvalidDataAccessApiUsageException("Pipeline is not supported for JedisClusterConnection."); } @Override public List closePipeline() throws RedisPipelineException { - throw new UnsupportedOperationException("Pipeline is currently not supported for JedisClusterConnection."); + throw new InvalidDataAccessApiUsageException("Pipeline is not supported for JedisClusterConnection."); } @Override public RedisSentinelConnection getSentinelConnection() { - throw new UnsupportedOperationException("Sentinel is currently not supported for JedisClusterConnection."); + throw new InvalidDataAccessApiUsageException("Sentinel is not supported for JedisClusterConnection."); } @Override @@ -709,7 +700,7 @@ static class JedisClusterNodeResourceProvider implements ClusterNodeResourceProv private final JedisCluster cluster; private final ClusterTopologyProvider topologyProvider; - private final JedisClusterConnectionHandler connectionHandler; + private final ClusterConnectionProvider connectionHandler; /** * Creates new {@link JedisClusterNodeResourceProvider}. @@ -726,7 +717,7 @@ static class JedisClusterNodeResourceProvider implements ClusterNodeResourceProv PropertyAccessor accessor = new DirectFieldAccessFallbackBeanWrapper(cluster); this.connectionHandler = accessor.isReadableProperty("connectionHandler") - ? (JedisClusterConnectionHandler) accessor.getPropertyValue("connectionHandler") + ? (ClusterConnectionProvider) accessor.getPropertyValue("connectionHandler") : null; } else { this.connectionHandler = null; @@ -739,23 +730,23 @@ public Jedis getResourceForSpecificNode(RedisClusterNode node) { Assert.notNull(node, "Cannot get Pool for 'null' node!"); - JedisPool pool = getResourcePoolForSpecificNode(node); + ConnectionPool pool = getResourcePoolForSpecificNode(node); if (pool != null) { - return pool.getResource(); + return new Jedis(pool.getResource()); } - Jedis connection = getConnectionForSpecificNode(node); + Connection connection = getConnectionForSpecificNode(node); if (connection != null) { - return connection; + return new Jedis(connection); } throw new DataAccessResourceFailureException(String.format("Node %s is unknown to cluster", node)); } - private JedisPool getResourcePoolForSpecificNode(RedisClusterNode node) { + private ConnectionPool getResourcePoolForSpecificNode(RedisClusterNode node) { - Map clusterNodes = cluster.getClusterNodes(); + Map clusterNodes = cluster.getClusterNodes(); if (clusterNodes.containsKey(node.asString())) { return clusterNodes.get(node.asString()); } @@ -763,7 +754,7 @@ private JedisPool getResourcePoolForSpecificNode(RedisClusterNode node) { return null; } - private Jedis getConnectionForSpecificNode(RedisClusterNode node) { + private Connection getConnectionForSpecificNode(RedisClusterNode node) { RedisClusterNode member = topologyProvider.getTopology().lookup(node); @@ -773,7 +764,7 @@ private Jedis getConnectionForSpecificNode(RedisClusterNode node) { } if (member != null && connectionHandler != null) { - return connectionHandler.getConnectionFromNode(new HostAndPort(member.getHost(), member.getPort())); + return connectionHandler.getConnection(new HostAndPort(member.getHost(), member.getPort())); } return null; @@ -835,15 +826,15 @@ public ClusterTopology getTopology() { Map errors = new LinkedHashMap<>(); - List> list = new ArrayList<>(cluster.getClusterNodes().entrySet()); + List> list = new ArrayList<>(cluster.getClusterNodes().entrySet()); Collections.shuffle(list); - for (Entry entry : list) { + for (Entry entry : list) { - try (Jedis jedis = entry.getValue().getResource()) { + try (Connection connection = entry.getValue().getResource()) { time = System.currentTimeMillis(); - Set nodes = Converters.toSetOfRedisClusterNodes(jedis.clusterNodes()); + Set nodes = Converters.toSetOfRedisClusterNodes(new Jedis(connection).clusterNodes()); synchronized (lock) { cached = new ClusterTopology(nodes); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java index 94c1033c82..30911ea8bd 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java @@ -16,8 +16,9 @@ package org.springframework.data.redis.connection.jedis; import redis.clients.jedis.GeoCoordinate; -import redis.clients.jedis.GeoUnit; +import redis.clients.jedis.args.GeoUnit; import redis.clients.jedis.params.GeoRadiusParam; +import redis.clients.jedis.params.GeoSearchParam; import java.util.HashMap; import java.util.List; @@ -238,13 +239,37 @@ public Long geoRemove(byte[] key, byte[]... members) { @Override public GeoResults> geoSearch(byte[] key, GeoReference reference, GeoShape predicate, GeoSearchCommandArgs args) { - throw new UnsupportedOperationException("GEOSEARCH not supported through Jedis"); + + Assert.notNull(key, "Key must not be null!"); + GeoSearchParam params = JedisConverters.toGeoSearchParams(reference, predicate, args); + + try { + + return JedisConverters.geoRadiusResponseToGeoResultsConverter(predicate.getMetric()) + .convert(connection.getCluster().geosearch(key, params)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } } @Override public Long geoSearchStore(byte[] destKey, byte[] key, GeoReference reference, GeoShape predicate, GeoSearchStoreCommandArgs args) { - throw new UnsupportedOperationException("GEOSEARCHSTORE not supported through Jedis"); + + Assert.notNull(destKey, "Destination Key must not be null!"); + Assert.notNull(key, "Key must not be null!"); + GeoSearchParam params = JedisConverters.toGeoSearchParams(reference, predicate, args); + + try { + + if (args.isStoreDistance()) { + return connection.getCluster().geosearchStoreStoreDist(destKey, key, params); + } + + return connection.getCluster().geosearchStore(destKey, key, params); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } } private DataAccessException convertJedisAccessException(Exception ex) { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java index f7628823c2..d48b78109b 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java @@ -15,7 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.ScanParams; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; import java.util.ArrayList; import java.util.Collections; @@ -278,8 +279,8 @@ protected ScanIteration> doScan(long cursorId, ScanOptions ScanParams params = JedisConverters.toScanParams(options); - redis.clients.jedis.ScanResult> result = connection.getCluster().hscan(key, - JedisConverters.toBytes(cursorId), params); + ScanResult> result = connection.getCluster().hscan(key, JedisConverters.toBytes(cursorId), + params); return new ScanIteration<>(Long.valueOf(result.getCursor()), result.getResult()); } }.open(); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java index 526aea0acd..578f0d5408 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java @@ -15,8 +15,9 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.ScanParams; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; import java.time.Duration; import java.util.ArrayList; @@ -179,7 +180,7 @@ Cursor scan(RedisClusterNode node, ScanOptions options) { protected ScanIteration doScan(long cursorId, ScanOptions options) { ScanParams params = JedisConverters.toScanParams(options); - redis.clients.jedis.ScanResult result = client.scan(Long.toString(cursorId), params); + ScanResult result = client.scan(Long.toString(cursorId), params); return new ScanIteration<>(Long.valueOf(result.getCursor()), JedisConverters.stringListToByteList().convert(result.getResult())); } @@ -277,11 +278,8 @@ public Boolean expire(byte[] key, long seconds) { Assert.notNull(key, "Key must not be null!"); - if (seconds > Integer.MAX_VALUE) { - throw new UnsupportedOperationException("Jedis does not support seconds exceeding Integer.MAX_VALUE."); - } try { - return JedisConverters.toBoolean(connection.getCluster().expire(key, Long.valueOf(seconds).intValue())); + return JedisConverters.toBoolean(connection.getCluster().expire(key, seconds)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -337,7 +335,7 @@ public Boolean persist(byte[] key) { @Override public Boolean move(byte[] key, int dbIndex) { - throw new UnsupportedOperationException("Cluster mode does not allow moving keys."); + throw new InvalidDataAccessApiUsageException("Cluster mode does not allow moving keys."); } @Override @@ -404,14 +402,10 @@ public void restore(byte[] key, long ttlInMillis, byte[] serializedValue, boolea Assert.notNull(key, "Key must not be null!"); Assert.notNull(serializedValue, "Serialized value must not be null!"); - if (ttlInMillis > Integer.MAX_VALUE) { - throw new UnsupportedOperationException("Jedis does not support ttlInMillis exceeding Integer.MAX_VALUE."); - } - connection.getClusterCommandExecutor().executeCommandOnSingleNode((JedisClusterCommandCallback) client -> { if (!replace) { - return client.restore(key, Long.valueOf(ttlInMillis).intValue(), serializedValue); + return client.restore(key, ttlInMillis, serializedValue); } return JedisConverters.toString(this.connection.execute("RESTORE", key, @@ -472,7 +466,7 @@ public Long exists(byte[]... keys) { } return connection.getClusterCommandExecutor() - .executeMultiKeyCommand((JedisMultiKeyClusterCommandCallback) BinaryJedis::exists, Arrays.asList(keys)) + .executeMultiKeyCommand((JedisMultiKeyClusterCommandCallback) Jedis::exists, Arrays.asList(keys)) .resultsAsList().stream().mapToLong(val -> ObjectUtils.nullSafeEquals(val, Boolean.TRUE) ? 1 : 0).sum(); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterScriptingCommands.java index 317959aef8..d55dd8a3bd 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterScriptingCommands.java @@ -15,7 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; +import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; import java.util.List; @@ -43,8 +43,8 @@ class JedisClusterScriptingCommands implements RedisScriptingCommands { public void scriptFlush() { try { - connection.getClusterCommandExecutor().executeCommandOnAllNodes( - (JedisClusterConnection.JedisClusterCommandCallback) BinaryJedis::scriptFlush); + connection.getClusterCommandExecutor() + .executeCommandOnAllNodes((JedisClusterConnection.JedisClusterCommandCallback) Jedis::scriptFlush); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -54,8 +54,8 @@ public void scriptFlush() { public void scriptKill() { try { - connection.getClusterCommandExecutor().executeCommandOnAllNodes( - (JedisClusterConnection.JedisClusterCommandCallback) BinaryJedis::scriptKill); + connection.getClusterCommandExecutor() + .executeCommandOnAllNodes((JedisClusterConnection.JedisClusterCommandCallback) Jedis::scriptKill); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -89,8 +89,7 @@ public T eval(byte[] script, ReturnType returnType, int numKeys, byte[]... k Assert.notNull(script, "Script must not be null!"); try { - return (T) new JedisScriptReturnConverter(returnType) - .convert(getCluster().eval(script, JedisConverters.toBytes(numKeys), keysAndArgs)); + return (T) new JedisScriptReturnConverter(returnType).convert(getCluster().eval(script, numKeys, keysAndArgs)); } catch (Exception ex) { throw convertJedisAccessException(ex); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterServerCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterServerCommands.java index 93e7ca42d9..015570739a 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterServerCommands.java @@ -15,7 +15,6 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; import redis.clients.jedis.Jedis; import java.util.ArrayList; @@ -54,30 +53,30 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { @Override public void bgReWriteAof(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::bgrewriteaof, node); + executeCommandOnSingleNode(Jedis::bgrewriteaof, node); } @Override public void bgReWriteAof() { connection.getClusterCommandExecutor() - .executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::bgrewriteaof); + .executeCommandOnAllNodes((JedisClusterCommandCallback) Jedis::bgrewriteaof); } @Override public void bgSave() { connection.getClusterCommandExecutor() - .executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::bgsave); + .executeCommandOnAllNodes((JedisClusterCommandCallback) Jedis::bgsave); } @Override public void bgSave(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::bgsave, node); + executeCommandOnSingleNode(Jedis::bgsave, node); } @Override public Long lastSave() { - List result = new ArrayList<>(executeCommandOnAllNodes(BinaryJedis::lastsave).resultsAsList()); + List result = new ArrayList<>(executeCommandOnAllNodes(Jedis::lastsave).resultsAsList()); if (CollectionUtils.isEmpty(result)) { return null; @@ -89,23 +88,23 @@ public Long lastSave() { @Override public Long lastSave(RedisClusterNode node) { - return executeCommandOnSingleNode(BinaryJedis::lastsave, node).getValue(); + return executeCommandOnSingleNode(Jedis::lastsave, node).getValue(); } @Override public void save() { - executeCommandOnAllNodes(BinaryJedis::save); + executeCommandOnAllNodes(Jedis::save); } @Override public void save(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::save, node); + executeCommandOnSingleNode(Jedis::save, node); } @Override public Long dbSize() { - Collection dbSizes = executeCommandOnAllNodes(BinaryJedis::dbSize).resultsAsList(); + Collection dbSizes = executeCommandOnAllNodes(Jedis::dbSize).resultsAsList(); if (CollectionUtils.isEmpty(dbSizes)) { return 0L; @@ -120,12 +119,12 @@ public Long dbSize() { @Override public Long dbSize(RedisClusterNode node) { - return executeCommandOnSingleNode(BinaryJedis::dbSize, node).getValue(); + return executeCommandOnSingleNode(Jedis::dbSize, node).getValue(); } @Override public void flushDb() { - executeCommandOnAllNodes(BinaryJedis::flushDB); + executeCommandOnAllNodes(Jedis::flushDB); } @Override @@ -135,7 +134,7 @@ public void flushDb(FlushOption option) { @Override public void flushDb(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::flushDB, node); + executeCommandOnSingleNode(Jedis::flushDB, node); } @Override @@ -146,19 +145,18 @@ public void flushDb(RedisClusterNode node, FlushOption option) { @Override public void flushAll() { connection.getClusterCommandExecutor() - .executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::flushAll); + .executeCommandOnAllNodes((JedisClusterCommandCallback) Jedis::flushAll); } @Override public void flushAll(FlushOption option) { - connection.getClusterCommandExecutor() - .executeCommandOnAllNodes( - (JedisClusterCommandCallback) it -> it.flushAll(JedisConverters.toFlushMode(option))); + connection.getClusterCommandExecutor().executeCommandOnAllNodes( + (JedisClusterCommandCallback) it -> it.flushAll(JedisConverters.toFlushMode(option))); } @Override public void flushAll(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::flushAll, node); + executeCommandOnSingleNode(Jedis::flushAll, node); } @Override @@ -187,7 +185,7 @@ public Properties info() { @Override public Properties info(RedisClusterNode node) { - return JedisConverters.toProperties(executeCommandOnSingleNode(BinaryJedis::info, node).getValue()); + return JedisConverters.toProperties(executeCommandOnSingleNode(Jedis::info, node).getValue()); } @Override @@ -221,13 +219,18 @@ public Properties info(RedisClusterNode node, String section) { @Override public void shutdown() { - connection.getClusterCommandExecutor() - .executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::shutdown); + connection.getClusterCommandExecutor().executeCommandOnAllNodes((JedisClusterCommandCallback) jedis -> { + jedis.shutdown(); + return null; + }); } @Override public void shutdown(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::shutdown, node); + executeCommandOnSingleNode(jedis -> { + jedis.shutdown(); + return null; + }, node); } @Override @@ -297,23 +300,23 @@ public void setConfig(RedisClusterNode node, String param, String value) { @Override public void resetConfigStats() { connection.getClusterCommandExecutor() - .executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::configResetStat); + .executeCommandOnAllNodes((JedisClusterCommandCallback) Jedis::configResetStat); } @Override public void rewriteConfig() { connection.getClusterCommandExecutor() - .executeCommandOnAllNodes((JedisClusterCommandCallback) BinaryJedis::configRewrite); + .executeCommandOnAllNodes((JedisClusterCommandCallback) Jedis::configRewrite); } @Override public void resetConfigStats(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::configResetStat, node); + executeCommandOnSingleNode(Jedis::configResetStat, node); } @Override public void rewriteConfig(RedisClusterNode node) { - executeCommandOnSingleNode(BinaryJedis::configRewrite, node); + executeCommandOnSingleNode(Jedis::configRewrite, node); } @Override @@ -321,7 +324,7 @@ public Long time(TimeUnit timeUnit) { return convertListOfStringToTime( connection.getClusterCommandExecutor() - .executeCommandOnArbitraryNode((JedisClusterCommandCallback>) BinaryJedis::time).getValue(), + .executeCommandOnArbitraryNode((JedisClusterCommandCallback>) Jedis::time).getValue(), timeUnit); } @@ -330,7 +333,7 @@ public Long time(RedisClusterNode node, TimeUnit timeUnit) { return convertListOfStringToTime( connection.getClusterCommandExecutor() - .executeCommandOnSingleNode((JedisClusterCommandCallback>) BinaryJedis::time, node).getValue(), + .executeCommandOnSingleNode((JedisClusterCommandCallback>) Jedis::time, node).getValue(), timeUnit); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java index caef5551da..b4698c240b 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java @@ -15,7 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.ScanParams; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; import java.util.ArrayList; import java.util.Arrays; @@ -396,8 +397,7 @@ public Cursor sScan(byte[] key, ScanOptions options) { protected ScanIteration doScan(long cursorId, ScanOptions options) { ScanParams params = JedisConverters.toScanParams(options); - redis.clients.jedis.ScanResult result = connection.getCluster().sscan(key, - JedisConverters.toBytes(cursorId), params); + ScanResult result = connection.getCluster().sscan(key, JedisConverters.toBytes(cursorId), params); return new ScanIteration<>(Long.parseLong(result.getCursor()), result.getResult()); } }.open(); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStreamCommands.java index c0092fde95..e73c7c4984 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStreamCommands.java @@ -19,7 +19,11 @@ import redis.clients.jedis.BuilderFactory; import redis.clients.jedis.params.XAddParams; +import redis.clients.jedis.params.XClaimParams; +import redis.clients.jedis.params.XReadGroupParams; +import redis.clients.jedis.params.XReadParams; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -73,7 +77,7 @@ public RecordId xAdd(MapRecord record, XAddOptions optio Assert.notNull(record, "Record must not be null!"); Assert.notNull(record.getStream(), "Stream must not be null!"); - XAddParams params = StreamConverters.toXAddParams(record, options); + XAddParams params = StreamConverters.toXAddParams(record.getId(), options); try { return RecordId @@ -85,7 +89,26 @@ public RecordId xAdd(MapRecord record, XAddOptions optio @Override public List xClaimJustId(byte[] key, String group, String newOwner, XClaimOptions options) { - throw new UnsupportedOperationException("JedisCluster does not support xClaimJustId."); + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(group, "Group must not be null!"); + Assert.notNull(newOwner, "NewOwner must not be null!"); + + long minIdleTime = options.getMinIdleTime() == null ? -1L : options.getMinIdleTime().toMillis(); + + XClaimParams xClaimParams = StreamConverters.toXClaimParams(options); + try { + + List ids = connection.getCluster().xclaimJustId(key, JedisConverters.toBytes(group), + JedisConverters.toBytes(newOwner), minIdleTime, xClaimParams, entryIdsToBytes(options.getIds())); + + List recordIds = new ArrayList<>(ids.size()); + ids.forEach(it -> recordIds.add(RecordId.of(JedisConverters.toString(it)))); + + return recordIds; + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } } @Override @@ -96,13 +119,11 @@ public List xClaim(byte[] key, String group, String newOwner, XClaim Assert.notNull(newOwner, "NewOwner must not be null!"); long minIdleTime = options.getMinIdleTime() == null ? -1L : options.getMinIdleTime().toMillis(); - int retryCount = options.getRetryCount() == null ? -1 : options.getRetryCount().intValue(); - long unixTime = options.getUnixTime() == null ? -1L : options.getUnixTime().toEpochMilli(); + XClaimParams xClaimParams = StreamConverters.toXClaimParams(options); try { - return convertToByteRecord(key, - connection.getCluster().xclaim(key, JedisConverters.toBytes(group), JedisConverters.toBytes(newOwner), - minIdleTime, unixTime, retryCount, options.isForce(), entryIdsToBytes(options.getIds()))); + return convertToByteRecord(key, connection.getCluster().xclaim(key, JedisConverters.toBytes(group), + JedisConverters.toBytes(newOwner), minIdleTime, xClaimParams, entryIdsToBytes(options.getIds()))); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -170,17 +191,40 @@ public Boolean xGroupDestroy(byte[] key, String groupName) { @Override public StreamInfo.XInfoStream xInfo(byte[] key) { - throw new UnsupportedOperationException("JedisCluster does not support XINFO."); + + Assert.notNull(key, "Key must not be null!"); + + try { + return StreamInfo.XInfoStream.fromList((List) connection.getCluster().xinfoStream(key)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } } @Override public StreamInfo.XInfoGroups xInfoGroups(byte[] key) { - throw new UnsupportedOperationException("JedisCluster does not support XINFO."); + + Assert.notNull(key, "Key must not be null!"); + + try { + return StreamInfo.XInfoGroups.fromList(connection.getCluster().xinfoGroups(key)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } } @Override public StreamInfo.XInfoConsumers xInfoConsumers(byte[] key, String groupName) { - throw new UnsupportedOperationException("JedisCluster does not support XINFO."); + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(groupName, "GroupName must not be null!"); + + try { + return StreamInfo.XInfoConsumers.fromList(groupName, + connection.getCluster().xinfoConsumers(key, JedisConverters.toBytes(groupName))); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } } @Override @@ -197,7 +241,21 @@ public Long xLen(byte[] key) { @Override public PendingMessagesSummary xPending(byte[] key, String groupName) { - throw new UnsupportedOperationException("Jedis does not support returning PendingMessagesSummary."); + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(groupName, "GroupName must not be null!"); + + byte[] group = JedisConverters.toBytes(groupName); + + try { + + Object response = connection.getCluster().xpending(key, group); + + return StreamConverters.toPendingMessagesSummary(groupName, response); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } @Override @@ -245,12 +303,11 @@ public List xRead(StreamReadOptions readOptions, StreamOffset xread = connection.getCluster().xread(count, block, toStreamOffsets(streams)); + List xread = connection.getCluster().xread(xReadParams, toStreamOffsets(streams)); if (xread == null) { return Collections.emptyList(); @@ -270,13 +327,12 @@ public List xReadGroup(Consumer consumer, StreamReadOptions readOpti Assert.notNull(readOptions, "StreamReadOptions must not be null!"); Assert.notNull(streams, "StreamOffsets must not be null!"); - long block = readOptions.getBlock() == null ? -1L : readOptions.getBlock(); - int count = readOptions.getCount() == null ? -1 : readOptions.getCount().intValue(); + XReadGroupParams xReadParams = StreamConverters.toXReadGroupParams(readOptions); try { List xread = connection.getCluster().xreadGroup(JedisConverters.toBytes(consumer.getGroup()), - JedisConverters.toBytes(consumer.getName()), count, block, readOptions.isNoack(), toStreamOffsets(streams)); + JedisConverters.toBytes(consumer.getName()), xReadParams, toStreamOffsets(streams)); if (xread == null) { return Collections.emptyList(); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java index 68599f7b75..617fbc52cd 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java @@ -15,8 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.Connection; +import redis.clients.jedis.Jedis; import redis.clients.jedis.params.SetParams; import java.util.ArrayList; @@ -116,7 +115,7 @@ public List mGet(byte[]... keys) { } return connection.getClusterCommandExecutor() - .executeMultiKeyCommand((JedisMultiKeyClusterCommandCallback) BinaryJedis::get, Arrays.asList(keys)) + .executeMultiKeyCommand((JedisMultiKeyClusterCommandCallback) Jedis::get, Arrays.asList(keys)) .resultsAsListSortBy(keys); } @@ -393,7 +392,7 @@ public List bitField(byte[] key, BitFieldSubCommands subCommands) { byte[][] args = JedisConverters.toBitfieldCommandArguments(subCommands); try { - return connection.execute("BITFIELD", key, Arrays.asList(args), Connection::getIntegerMultiBulkReply); + return connection.getCluster().bitfield(key, args); } catch (Exception ex) { throw convertJedisAccessException(ex); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java index 9e92134a1c..e4376b14b5 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java @@ -15,10 +15,12 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ZParams; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.params.ZParams; +import redis.clients.jedis.resps.ScanResult; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -49,7 +51,7 @@ */ class JedisClusterZSetCommands implements RedisZSetCommands { - private static final SetConverter TUPLE_SET_CONVERTER = new SetConverter<>( + private static final SetConverter TUPLE_SET_CONVERTER = new SetConverter<>( JedisConverters::toTuple); private final JedisClusterConnection connection; @@ -142,7 +144,7 @@ public Tuple zRandMemberWithScore(byte[] key) { Assert.notNull(key, "Key must not be null!"); try { - Set tuples = connection.getCluster().zrandmemberWithScores(key, 1); + List tuples = connection.getCluster().zrandmemberWithScores(key, 1); return tuples.isEmpty() ? null : JedisConverters.toTuple(tuples.iterator().next()); } catch (Exception ex) { @@ -156,7 +158,7 @@ public List zRandMemberWithScore(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); try { - Set tuples = connection.getCluster().zrandmemberWithScores(key, count); + List tuples = connection.getCluster().zrandmemberWithScores(key, count); return tuples.stream().map(JedisConverters::toTuple).collect(Collectors.toList()); } catch (Exception ex) { @@ -196,7 +198,7 @@ public Set zRange(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zrange(key, start, end); + return new LinkedHashSet<>(connection.getCluster().zrange(key, start, end)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -234,9 +236,10 @@ public Set zRevRangeByScore(byte[] key, Range range, org.springframework try { if (limit.isUnlimited()) { - return connection.getCluster().zrevrangeByScore(key, max, min); + return new LinkedHashSet<>(connection.getCluster().zrevrangeByScore(key, max, min)); } - return connection.getCluster().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); + return new LinkedHashSet<>( + connection.getCluster().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -302,7 +305,7 @@ public Tuple zPopMin(byte[] key) { Assert.notNull(key, "Key must not be null!"); try { - redis.clients.jedis.Tuple tuple = connection.getCluster().zpopmin(key); + redis.clients.jedis.resps.Tuple tuple = connection.getCluster().zpopmin(key); return tuple != null ? JedisConverters.toTuple(tuple) : null; } catch (Exception ex) { throw convertJedisAccessException(ex); @@ -343,7 +346,7 @@ public Tuple zPopMax(byte[] key) { Assert.notNull(key, "Key must not be null!"); try { - redis.clients.jedis.Tuple tuple = connection.getCluster().zpopmax(key); + redis.clients.jedis.resps.Tuple tuple = connection.getCluster().zpopmax(key); return tuple != null ? JedisConverters.toTuple(tuple) : null; } catch (Exception ex) { throw convertJedisAccessException(ex); @@ -405,9 +408,10 @@ public Set zRangeByScore(byte[] key, Range range, org.springframework.da try { if (limit.isUnlimited()) { - return connection.getCluster().zrangeByScore(key, min, max); + return new LinkedHashSet<>(connection.getCluster().zrangeByScore(key, min, max)); } - return connection.getCluster().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); + return new LinkedHashSet<>( + connection.getCluster().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -425,9 +429,10 @@ public Set zRangeByLex(byte[] key, Range range, org.springframework.data try { if (limit.isUnlimited()) { - return connection.getCluster().zrangeByLex(key, min, max); + return new LinkedHashSet<>(connection.getCluster().zrangeByLex(key, min, max)); } - return connection.getCluster().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); + return new LinkedHashSet<>( + connection.getCluster().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -461,9 +466,10 @@ public Set zRevRangeByLex(byte[] key, Range range, org.springframework.d try { if (limit.isUnlimited()) { - return connection.getCluster().zrevrangeByLex(key, max, min); + return new LinkedHashSet<>(connection.getCluster().zrevrangeByLex(key, max, min)); } - return connection.getCluster().zrevrangeByLex(key, max, min, limit.getOffset(), limit.getCount()); + return new LinkedHashSet<>( + connection.getCluster().zrevrangeByLex(key, max, min, limit.getOffset(), limit.getCount())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -487,7 +493,7 @@ public Set zRangeByScore(byte[] key, double min, double max) { Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zrangeByScore(key, min, max); + return new LinkedHashSet<>(connection.getCluster().zrangeByScore(key, min, max)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -515,8 +521,8 @@ public Set zRangeByScore(byte[] key, double min, double max, long offset } try { - return connection.getCluster().zrangeByScore(key, min, max, Long.valueOf(offset).intValue(), - Long.valueOf(count).intValue()); + return new LinkedHashSet<>(connection.getCluster().zrangeByScore(key, min, max, Long.valueOf(offset).intValue(), + Long.valueOf(count).intValue())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -545,7 +551,7 @@ public Set zRevRange(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zrevrange(key, start, end); + return new LinkedHashSet<>(connection.getCluster().zrevrange(key, start, end)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -569,7 +575,7 @@ public Set zRevRangeByScore(byte[] key, double min, double max) { Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zrevrangeByScore(key, max, min); + return new LinkedHashSet<>(connection.getCluster().zrevrangeByScore(key, max, min)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -597,8 +603,8 @@ public Set zRevRangeByScore(byte[] key, double min, double max, long off } try { - return connection.getCluster().zrevrangeByScore(key, max, min, Long.valueOf(offset).intValue(), - Long.valueOf(count).intValue()); + return new LinkedHashSet<>(connection.getCluster().zrevrangeByScore(key, max, min, + Long.valueOf(offset).intValue(), Long.valueOf(count).intValue())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -961,7 +967,7 @@ protected ScanIteration doScan(long cursorId, ScanOptions options) { ScanParams params = JedisConverters.toScanParams(options); - redis.clients.jedis.ScanResult result = connection.getCluster().zscan(key, + ScanResult result = connection.getCluster().zscan(key, JedisConverters.toBytes(cursorId), params); return new ScanIteration<>(Long.valueOf(result.getCursor()), JedisConverters.tuplesToTuples().convert(result.getResult())); @@ -975,7 +981,8 @@ public Set zRangeByScore(byte[] key, String min, String max) { Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max)); + return new LinkedHashSet<>( + connection.getCluster().zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max))); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -991,8 +998,8 @@ public Set zRangeByScore(byte[] key, String min, String max, long offset } try { - return connection.getCluster().zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max), - Long.valueOf(offset).intValue(), Long.valueOf(count).intValue()); + return new LinkedHashSet<>(connection.getCluster().zrangeByScore(key, JedisConverters.toBytes(min), + JedisConverters.toBytes(max), Long.valueOf(offset).intValue(), Long.valueOf(count).intValue())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -1002,7 +1009,7 @@ private DataAccessException convertJedisAccessException(Exception ex) { return connection.convertJedisAccessException(ex); } - private static Set toTupleSet(Set source) { + private static Set toTupleSet(List source) { return TUPLE_SET_CONVERTER.convert(source); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index de9a22de0f..ffcf5200c1 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -15,7 +15,18 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.*; +import redis.clients.jedis.BuilderFactory; +import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.CommandObject; +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisClientConfig; +import redis.clients.jedis.Pipeline; +import redis.clients.jedis.Response; +import redis.clients.jedis.Transaction; +import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.commands.ServerCommands; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.util.Pool; @@ -36,6 +47,7 @@ import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.connection.*; import org.springframework.data.redis.connection.convert.TransactionResultConverter; +import org.springframework.data.redis.connection.jedis.JedisInvoker.ResponseCommands; import org.springframework.data.redis.connection.jedis.JedisResult.JedisResultBuilder; import org.springframework.data.redis.connection.jedis.JedisResult.JedisStatusResult; import org.springframework.lang.Nullable; @@ -43,7 +55,7 @@ import org.springframework.util.CollectionUtils; /** - * {@code RedisConnection} implementation on top of Jedis library. + * {@code RedisConnection} implementation on top of Jedis library. * * @author Costin Leau * @author Jennifer Hickey @@ -83,11 +95,8 @@ public class JedisConnection extends AbstractRedisConnection { private final JedisZSetCommands zSetCommands = new JedisZSetCommands(this); private final @Nullable Pool pool; - private final String clientName; - private final JedisClientConfig nodeConfig; private final JedisClientConfig sentinelConfig; - private List pipelinedResults = new ArrayList<>(); private Queue>> txResults = new LinkedList<>(); @@ -148,8 +157,6 @@ protected JedisConnection(Jedis jedis, @Nullable Pool pool, JedisClientCo this.jedis = jedis; this.pool = pool; - this.clientName = nodeConfig.getClientName(); - this.nodeConfig = nodeConfig; this.sentinelConfig = sentinelConfig; // select the db @@ -167,22 +174,22 @@ protected JedisConnection(Jedis jedis, @Nullable Pool pool, JedisClientCo @Nullable private Object doInvoke(boolean status, Function directFunction, - Function> pipelineFunction, Converter converter, + Function> pipelineFunction, Converter converter, Supplier nullDefault) { return doWithJedis(it -> { - if (isPipelined()) { + if (isQueueing()) { - Response response = pipelineFunction.apply(getRequiredPipeline()); - pipeline(status ? newStatusResult(response) : newJedisResult(response, converter, nullDefault)); + Response response = pipelineFunction.apply(JedisInvoker.createCommands(getRequiredTransaction())); + transaction(status ? newStatusResult(response) : newJedisResult(response, converter, nullDefault)); return null; } - if (isQueueing()) { + if (isPipelined()) { - Response response = pipelineFunction.apply(getRequiredTransaction()); - transaction(status ? newStatusResult(response) : newJedisResult(response, converter, nullDefault)); + Response response = pipelineFunction.apply(JedisInvoker.createCommands(getRequiredPipeline())); + pipeline(status ? newStatusResult(response) : newJedisResult(response, converter, nullDefault)); return null; } @@ -263,32 +270,27 @@ public RedisServerCommands serverCommands() { @Override public Object execute(String command, byte[]... args) { - return execute(command, args, Connection::getOne, JedisClientUtils::getResponse); - } - - @Nullable - T execute(String command, byte[][] args, Function resultMapper, - Function> pipelineResponseMapper) { Assert.hasText(command, "A valid command needs to be specified!"); Assert.notNull(args, "Arguments must not be null!"); return doWithJedis(it -> { - Client client = JedisClientUtils.sendCommand(command, args, it); + ProtocolCommand protocolCommand = () -> JedisConverters.toBytes(command); if (isQueueing() || isPipelined()) { - Response result = pipelineResponseMapper - .apply(isPipelined() ? getRequiredPipeline() : getRequiredTransaction()); + CommandArguments arguments = new CommandArguments(protocolCommand).addObjects(args); + CommandObject commandObject = new CommandObject<>(arguments, BuilderFactory.RAW_OBJECT); if (isPipelined()) { - pipeline(newJedisResult(result)); + pipeline(newJedisResult(getRequiredPipeline().executeCommand(commandObject))); } else { - transaction(newJedisResult(result)); + transaction(newJedisResult(getRequiredTransaction().executeCommand(commandObject))); } return null; } - return resultMapper.apply(client); + + return it.sendCommand(protocolCommand, args); }); } @@ -330,16 +332,21 @@ public boolean isClosed() { @Override public boolean isQueueing() { - return JedisClientUtils.isInMulti(jedis); + return transaction != null; } @Override public boolean isPipelined() { - return (pipeline != null); + return pipeline != null; } @Override public void openPipeline() { + + if (isQueueing()) { + throw new InvalidDataAccessApiUsageException("Cannot use Pipelining while a transaction is active"); + } + if (pipeline == null) { pipeline = jedis.pipelined(); } @@ -406,21 +413,17 @@ public byte[] echo(byte[] message) { Assert.notNull(message, "Message must not be null"); - return invoke().just(BinaryJedis::echo, MultiKeyPipelineBase::echo, message); + return invoke().just(j -> j.echo(message)); } @Override public String ping() { - return invoke().just(BinaryJedis::ping, MultiKeyPipelineBase::ping); + return invoke().just(ServerCommands::ping); } @Override public void discard() { try { - if (isPipelined()) { - pipeline(newStatusResult(getRequiredPipeline().discard())); - return; - } getRequiredTransaction().discard(); } catch (Exception ex) { throw convertJedisAccessException(ex); @@ -433,11 +436,6 @@ public void discard() { @Override public List exec() { try { - if (isPipelined()) { - pipeline(newJedisResult(getRequiredPipeline().exec(), - new TransactionResultConverter<>(new LinkedList<>(txResults), JedisExceptionConverter.INSTANCE))); - return null; - } if (transaction == null) { throw new InvalidDataAccessApiUsageException("No ongoing transaction. Did you forget to call multi?"); @@ -517,12 +515,6 @@ JedisResult newJedisResult(Response response) { return JedisResultBuilder. forResponse(response).build(); } - JedisResult newJedisResult(Response response, Converter converter) { - - return JedisResultBuilder. forResponse(response).mappedWith(converter) - .convertPipelineAndTxResults(convertPipelineAndTxResults).build(); - } - JedisResult newJedisResult(Response response, Converter converter, Supplier defaultValue) { return JedisResultBuilder. forResponse(response).mappedWith(converter) @@ -539,39 +531,34 @@ public void multi() { return; } - doWithJedis(it -> { + if (isPipelined()) { + throw new InvalidDataAccessApiUsageException("Cannot use Transaction while a pipeline is open"); + } - if (isPipelined()) { - getRequiredPipeline().multi(); - return; - } + doWithJedis(it -> { this.transaction = it.multi(); }); } @Override public void select(int dbIndex) { - invokeStatus().just(BinaryJedis::select, MultiKeyPipelineBase::select, dbIndex); + getJedis().select(dbIndex); } @Override public void unwatch() { - doWithJedis((Consumer) BinaryJedis::unwatch); + doWithJedis((Consumer) Jedis::unwatch); } @Override public void watch(byte[]... keys) { if (isQueueing()) { - throw new UnsupportedOperationException(); + throw new InvalidDataAccessApiUsageException("WATCH is not supported when a transaction is active"); } doWithJedis(it -> { for (byte[] key : keys) { - if (isPipelined()) { - pipeline(newStatusResult(getRequiredPipeline().watch(key))); - } else { - it.watch(key); - } + it.watch(key); } }); } @@ -582,7 +569,7 @@ public void watch(byte[]... keys) { @Override public Long publish(byte[] channel, byte[] message) { - return invoke().just(BinaryJedis::publish, MultiKeyPipelineBase::publish, channel, message); + return invoke().just(j -> j.publish(channel, message)); } @Override @@ -604,7 +591,7 @@ public void pSubscribe(MessageListener listener, byte[]... patterns) { } if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException(); + throw new InvalidDataAccessApiUsageException("Cannot subscribe in pipeline / transaction mode"); } doWithJedis(it -> { @@ -625,7 +612,7 @@ public void subscribe(MessageListener listener, byte[]... channels) { } if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException(); + throw new InvalidDataAccessApiUsageException("Cannot subscribe in pipeline / transaction mode"); } doWithJedis(it -> { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java index c1d751e8d9..93ddc1c785 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; +import redis.clients.jedis.Connection; import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; @@ -23,7 +24,6 @@ import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisSentinelPool; -import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.Protocol; import redis.clients.jedis.util.Pool; @@ -108,8 +108,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, private boolean destroyed; /** - * Constructs a new JedisConnectionFactory instance with default settings (default connection pooling, no - * shard information). + * Constructs a new {@link JedisConnectionFactory} instance with default settings (default connection pooling). */ public JedisConnectionFactory() { this(new MutableJedisClientConfiguration()); @@ -129,7 +128,7 @@ private JedisConnectionFactory(JedisClientConfiguration clientConfig) { } /** - * Constructs a new JedisConnectionFactory instance using the given pool configuration. + * Constructs a new {@link JedisConnectionFactory} instance using the given pool configuration. * * @param poolConfig pool configuration */ @@ -274,7 +273,6 @@ protected Jedis fetchJedisConnector() { } private Jedis createJedis() { - return new Jedis(new HostAndPort(getHostName(), getPort()), this.clientConfig); } @@ -401,7 +399,7 @@ protected ClusterTopologyProvider createTopologyProvider(JedisCluster cluster) { * @since 1.7 */ protected JedisCluster createCluster(RedisClusterConfiguration clusterConfig, - GenericObjectPoolConfig poolConfig) { + GenericObjectPoolConfig poolConfig) { Assert.notNull(clusterConfig, "Cluster configuration must not be null!"); @@ -649,7 +647,7 @@ public void setUsePool(boolean usePool) { * @return the poolConfig */ @Nullable - public GenericObjectPoolConfig getPoolConfig() { + public GenericObjectPoolConfig getPoolConfig() { return clientConfiguration.getPoolConfig().orElse(null); } @@ -835,7 +833,6 @@ private Jedis getActiveSentinel() { throw new InvalidDataAccessResourceUsageException("No Sentinel found"); } - private static Set convertToJedisSentinelSet(Collection nodes) { if (CollectionUtils.isEmpty(nodes)) { @@ -890,12 +887,6 @@ static class MutableJedisClientConfiguration implements JedisClientConfiguration private Duration readTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT); private Duration connectTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT); - public static JedisClientConfiguration create(JedisShardInfo shardInfo) { - - MutableJedisClientConfiguration configuration = new MutableJedisClientConfiguration(); - return configuration; - } - public static JedisClientConfiguration create(GenericObjectPoolConfig jedisPoolConfig) { MutableJedisClientConfiguration configuration = new MutableJedisClientConfiguration(); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java index fa10a250f3..8b72d3fd06 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java @@ -15,25 +15,25 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BitOP; import redis.clients.jedis.GeoCoordinate; -import redis.clients.jedis.GeoRadiusResponse; -import redis.clients.jedis.GeoUnit; -import redis.clients.jedis.ListPosition; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.SortingParams; +import redis.clients.jedis.args.BitOP; import redis.clients.jedis.args.FlushMode; +import redis.clients.jedis.args.GeoUnit; +import redis.clients.jedis.args.ListPosition; import redis.clients.jedis.params.GeoRadiusParam; +import redis.clients.jedis.params.GeoSearchParam; import redis.clients.jedis.params.GetExParams; +import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.params.SortingParams; import redis.clients.jedis.params.ZAddParams; +import redis.clients.jedis.resps.GeoRadiusResponse; import redis.clients.jedis.util.SafeEncoder; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.core.convert.converter.Converter; +import org.springframework.data.domain.Sort; import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResult; import org.springframework.data.geo.GeoResults; @@ -52,6 +53,7 @@ import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSet; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSubCommand; import org.springframework.data.redis.connection.RedisClusterNode; +import org.springframework.data.redis.connection.RedisGeoCommands; import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; @@ -76,6 +78,11 @@ import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.data.redis.domain.geo.BoundingBox; +import org.springframework.data.redis.domain.geo.BoxShape; +import org.springframework.data.redis.domain.geo.GeoReference; +import org.springframework.data.redis.domain.geo.GeoShape; +import org.springframework.data.redis.domain.geo.RadiusShape; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -94,7 +101,7 @@ * @author dengliming */ @SuppressWarnings("ConstantConditions") -public abstract class JedisConverters extends Converters { +abstract class JedisConverters extends Converters { public static final byte[] PLUS_BYTES; public static final byte[] MINUS_BYTES; @@ -114,12 +121,12 @@ public static Converter stringToBytes() { } /** - * {@link ListConverter} converting jedis {@link redis.clients.jedis.Tuple} to {@link Tuple}. + * {@link ListConverter} converting jedis {@link redis.clients.jedis.resps.Tuple} to {@link Tuple}. * * @return * @since 1.4 */ - static ListConverter tuplesToTuples() { + static ListConverter tuplesToTuples() { return new ListConverter<>(JedisConverters::toTuple); } @@ -127,14 +134,11 @@ static ListConverter stringListToByteList() { return new ListConverter<>(stringToBytes()); } - /** - * @deprecated since 2.5 - */ - static Set toTupleSet(Set source) { + static Set toTupleSet(Set source) { return new SetConverter<>(JedisConverters::toTuple).convert(source); } - public static Tuple toTuple(redis.clients.jedis.Tuple source) { + public static Tuple toTuple(redis.clients.jedis.resps.Tuple source) { return new DefaultTuple(source.getBinaryElement(), source.getScore()); } @@ -150,10 +154,8 @@ public static Map toTupleMap(Set tuples) { Assert.notNull(tuples, "Tuple set must not be null!"); Map args = new LinkedHashMap<>(tuples.size(), 1); - Set scores = new HashSet<>(tuples.size(), 1); for (Tuple tuple : tuples) { - scores.add(tuple.getScore()); args.put(tuple.getValue(), tuple.getScore()); } @@ -238,7 +240,6 @@ public static List toListOfRedisClientInformation(String source * @since 1.4 */ public static List toListOfRedisServer(List> source) { - return toList(it -> RedisServer.newServerFrom(Converters.toProperties(it)), source); } @@ -586,7 +587,7 @@ public static GeoCoordinate toGeoCoordinate(Point source) { * @return * @since 1.8 */ - public static Converter, GeoResults>> geoRadiusResponseToGeoResultsConverter( + public static Converter, GeoResults>> geoRadiusResponseToGeoResultsConverter( Metric metric) { return GeoResultsConverterFactory.INSTANCE.forMetric(metric); } @@ -759,6 +760,86 @@ static FlushMode toFlushMode(@Nullable RedisServerCommands.FlushOption option) { } } + static GeoSearchParam toGeoSearchParams(GeoReference reference, GeoShape predicate, + RedisGeoCommands.GeoCommandArgs args) { + + Assert.notNull(reference, "GeoReference must not be null!"); + Assert.notNull(predicate, "GeoShape must not be null!"); + Assert.notNull(args, "GeoSearchCommandArgs must not be null!"); + + GeoSearchParam param = GeoSearchParam.geoSearchParam(); + + configureGeoReference(reference, param); + + if (args.getLimit() != null) { + + boolean hasAnyLimit = args.getFlags().contains(Flag.ANY); + param.count(Math.toIntExact(args.getLimit()), hasAnyLimit); + } + + if (args.getSortDirection() != null) { + + if (args.getSortDirection() == Sort.Direction.ASC) { + param.asc(); + } else { + param.desc(); + } + } + + if (args.getFlags().contains(Flag.WITHDIST)) { + param.withDist(); + } + + if (args.getFlags().contains(Flag.WITHCOORD)) { + param.withCoord(); + } + + return getGeoSearchParam(predicate, param); + } + + private static GeoSearchParam getGeoSearchParam(GeoShape predicate, GeoSearchParam param) { + + if (predicate instanceof RadiusShape) { + + Distance radius = ((RadiusShape) predicate).getRadius(); + + param.byRadius(radius.getValue(), toGeoUnit(radius.getMetric())); + + return param; + } + + if (predicate instanceof BoxShape) { + + BoxShape boxPredicate = (BoxShape) predicate; + BoundingBox boundingBox = boxPredicate.getBoundingBox(); + + param.byBox(boundingBox.getWidth().getValue(), boundingBox.getHeight().getValue(), + toGeoUnit(boxPredicate.getMetric())); + + return param; + } + + throw new IllegalArgumentException(String.format("Cannot convert %s to Jedis GeoSearchParam", predicate)); + } + + private static void configureGeoReference(GeoReference reference, GeoSearchParam param) { + + if (reference instanceof GeoReference.GeoMemberReference) { + + param.fromMember(toString(((GeoReference.GeoMemberReference) reference).getMember())); + return; + } + + if (reference instanceof GeoReference.GeoCoordinateReference) { + + GeoReference.GeoCoordinateReference coordinates = (GeoReference.GeoCoordinateReference) reference; + param.fromLonLat(coordinates.getLongitude(), coordinates.getLatitude()); + return; + } + + throw new IllegalArgumentException(String.format("Cannot extract Geo Reference from %s", reference)); + } + /** * @author Christoph Strobl * @since 1.8 @@ -767,13 +848,13 @@ enum GeoResultsConverterFactory { INSTANCE; - Converter, GeoResults>> forMetric(Metric metric) { + Converter, GeoResults>> forMetric(Metric metric) { return new GeoResultsConverter( ObjectUtils.nullSafeEquals(Metrics.NEUTRAL, metric) ? DistanceUnit.METERS : metric); } private static class GeoResultsConverter - implements Converter, GeoResults>> { + implements Converter, GeoResults>> { private final Metric metric; @@ -786,7 +867,7 @@ public GeoResults> convert(List source) { List>> results = new ArrayList<>(source.size()); - Converter>> converter = GeoResultConverterFactory.INSTANCE + Converter>> converter = GeoResultConverterFactory.INSTANCE .forMetric(metric); for (GeoRadiusResponse result : source) { results.add(converter.convert(result)); @@ -805,12 +886,11 @@ enum GeoResultConverterFactory { INSTANCE; - Converter>> forMetric(Metric metric) { + Converter>> forMetric(Metric metric) { return new GeoResultConverter(metric); } - private static class GeoResultConverter - implements Converter>> { + private static class GeoResultConverter implements Converter>> { private final Metric metric; @@ -819,7 +899,7 @@ public GeoResultConverter(Metric metric) { } @Override - public GeoResult> convert(redis.clients.jedis.GeoRadiusResponse source) { + public GeoResult> convert(GeoRadiusResponse source) { Point point = JedisConverters.toPoint(source.getCoordinate()); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverter.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverter.java index 278793faf3..b3c34969f9 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverter.java @@ -15,7 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.exceptions.JedisClusterMaxAttemptsException; +import redis.clients.jedis.exceptions.JedisClusterOperationException; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.exceptions.JedisRedirectionException; @@ -49,7 +49,11 @@ public DataAccessException convert(Exception ex) { return (DataAccessException) ex; } - if (ex instanceof JedisClusterMaxAttemptsException) { + if (ex instanceof UnsupportedOperationException) { + return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); + } + + if (ex instanceof JedisClusterOperationException && "No more cluster attempts left.".equals(ex.getMessage())) { return new TooManyClusterRedirectionsException(ex.getMessage(), ex); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java index 6c232eb386..1efc1fd329 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java @@ -15,12 +15,11 @@ */ package org.springframework.data.redis.connection.jedis; -import org.springframework.data.redis.domain.geo.GeoReference; -import org.springframework.data.redis.domain.geo.GeoShape; -import redis.clients.jedis.BinaryJedis; import redis.clients.jedis.GeoCoordinate; -import redis.clients.jedis.GeoUnit; -import redis.clients.jedis.MultiKeyPipelineBase; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.args.GeoUnit; +import redis.clients.jedis.commands.PipelineBinaryCommands; +import redis.clients.jedis.params.GeoSearchParam; import java.util.HashMap; import java.util.List; @@ -33,6 +32,8 @@ import org.springframework.data.geo.Metric; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.domain.geo.GeoReference; +import org.springframework.data.redis.domain.geo.GeoShape; import org.springframework.util.Assert; /** @@ -55,7 +56,7 @@ public Long geoAdd(byte[] key, Point point, byte[] member) { Assert.notNull(point, "Point must not be null!"); Assert.notNull(member, "Member must not be null!"); - return connection.invoke().just(BinaryJedis::geoadd, MultiKeyPipelineBase::geoadd, key, point.getX(), point.getY(), + return connection.invoke().just(Jedis::geoadd, PipelineBinaryCommands::geoadd, key, point.getX(), point.getY(), member); } @@ -71,7 +72,7 @@ public Long geoAdd(byte[] key, Map memberCoordinateMap) { redisGeoCoordinateMap.put(mapKey, JedisConverters.toGeoCoordinate(memberCoordinateMap.get(mapKey))); } - return connection.invoke().just(BinaryJedis::geoadd, MultiKeyPipelineBase::geoadd, key, redisGeoCoordinateMap); + return connection.invoke().just(Jedis::geoadd, PipelineBinaryCommands::geoadd, key, redisGeoCoordinateMap); } @Override @@ -86,7 +87,7 @@ public Long geoAdd(byte[] key, Iterable> locations) { redisGeoCoordinateMap.put(location.getName(), JedisConverters.toGeoCoordinate(location.getPoint())); } - return connection.invoke().just(BinaryJedis::geoadd, MultiKeyPipelineBase::geoadd, key, redisGeoCoordinateMap); + return connection.invoke().just(Jedis::geoadd, PipelineBinaryCommands::geoadd, key, redisGeoCoordinateMap); } @Override @@ -98,7 +99,7 @@ public Distance geoDist(byte[] key, byte[] member1, byte[] member2) { Converter distanceConverter = JedisConverters.distanceConverterForMetric(DistanceUnit.METERS); - return connection.invoke().from(BinaryJedis::geodist, MultiKeyPipelineBase::geodist, key, member1, member2) + return connection.invoke().from(Jedis::geodist, PipelineBinaryCommands::geodist, key, member1, member2) .get(distanceConverter); } @@ -113,7 +114,7 @@ public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metri GeoUnit geoUnit = JedisConverters.toGeoUnit(metric); Converter distanceConverter = JedisConverters.distanceConverterForMetric(metric); - return connection.invoke().from(BinaryJedis::geodist, MultiKeyPipelineBase::geodist, key, member1, member2, geoUnit) + return connection.invoke().from(Jedis::geodist, PipelineBinaryCommands::geodist, key, member1, member2, geoUnit) .get(distanceConverter); } @@ -124,7 +125,7 @@ public List geoHash(byte[] key, byte[]... members) { Assert.notNull(members, "Members must not be null!"); Assert.noNullElements(members, "Members must not contain null!"); - return connection.invoke().fromMany(BinaryJedis::geohash, MultiKeyPipelineBase::geohash, key, members) + return connection.invoke().fromMany(Jedis::geohash, PipelineBinaryCommands::geohash, key, members) .toList(JedisConverters::toString); } @@ -135,7 +136,7 @@ public List geoPos(byte[] key, byte[]... members) { Assert.notNull(members, "Members must not be null!"); Assert.noNullElements(members, "Members must not contain null!"); - return connection.invoke().fromMany(BinaryJedis::geopos, MultiKeyPipelineBase::geopos, key, members) + return connection.invoke().fromMany(Jedis::geopos, PipelineBinaryCommands::geopos, key, members) .toList(JedisConverters::toPoint); } @@ -145,11 +146,11 @@ public GeoResults> geoRadius(byte[] key, Circle within) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(within, "Within must not be null!"); - Converter, GeoResults>> converter = JedisConverters + Converter, GeoResults>> converter = JedisConverters .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); return connection.invoke() - .from(BinaryJedis::georadius, MultiKeyPipelineBase::georadius, key, within.getCenter().getX(), + .from(Jedis::georadius, PipelineBinaryCommands::georadius, key, within.getCenter().getX(), within.getCenter().getY(), within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric())) .get(converter); @@ -163,11 +164,11 @@ public GeoResults> geoRadius(byte[] key, Circle within, GeoR Assert.notNull(args, "Args must not be null!"); redis.clients.jedis.params.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); - Converter, GeoResults>> converter = JedisConverters + Converter, GeoResults>> converter = JedisConverters .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); - return connection.invoke().from(BinaryJedis::georadius, MultiKeyPipelineBase::georadius, key, - within.getCenter().getX(), + return connection.invoke() + .from(Jedis::georadius, PipelineBinaryCommands::georadius, key, within.getCenter().getX(), within.getCenter().getY(), within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam) .get(converter); @@ -181,11 +182,11 @@ public GeoResults> geoRadiusByMember(byte[] key, byte[] memb Assert.notNull(radius, "Radius must not be null!"); GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); - Converter, GeoResults>> converter = JedisConverters + Converter, GeoResults>> converter = JedisConverters .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); - return connection.invoke().from(BinaryJedis::georadiusByMember, MultiKeyPipelineBase::georadiusByMember, key, - member, radius.getValue(), geoUnit).get(converter); + return connection.invoke().from(Jedis::georadiusByMember, PipelineBinaryCommands::georadiusByMember, key, member, + radius.getValue(), geoUnit).get(converter); } @Override @@ -198,12 +199,12 @@ public GeoResults> geoRadiusByMember(byte[] key, byte[] memb Assert.notNull(args, "Args must not be null!"); GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); - Converter, GeoResults>> converter = JedisConverters + Converter, GeoResults>> converter = JedisConverters .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); redis.clients.jedis.params.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); - return connection.invoke().from(BinaryJedis::georadiusByMember, MultiKeyPipelineBase::georadiusByMember, key, - member, radius.getValue(), geoUnit, geoRadiusParam).get(converter); + return connection.invoke().from(Jedis::georadiusByMember, PipelineBinaryCommands::georadiusByMember, key, member, + radius.getValue(), geoUnit, geoRadiusParam).get(converter); } @Override @@ -214,12 +215,30 @@ public Long geoRemove(byte[] key, byte[]... members) { @Override public GeoResults> geoSearch(byte[] key, GeoReference reference, GeoShape predicate, GeoSearchCommandArgs args) { - throw new UnsupportedOperationException("GEOSEARCH not supported through Jedis"); + + Assert.notNull(key, "Key must not be null!"); + + GeoSearchParam param = JedisConverters.toGeoSearchParams(reference, predicate, args); + Converter, GeoResults>> converter = JedisConverters + .geoRadiusResponseToGeoResultsConverter(predicate.getMetric()); + + return connection.invoke().from(Jedis::geosearch, PipelineBinaryCommands::geosearch, key, param).get(converter); } @Override public Long geoSearchStore(byte[] destKey, byte[] key, GeoReference reference, GeoShape predicate, GeoSearchStoreCommandArgs args) { - throw new UnsupportedOperationException("GEOSEARCHSTORE not supported through Jedis"); + + Assert.notNull(destKey, "Destination Key must not be null!"); + Assert.notNull(key, "Key must not be null!"); + + GeoSearchParam param = JedisConverters.toGeoSearchParams(reference, predicate, args); + + if (args.isStoreDistance()) { + return connection.invoke().just(Jedis::geosearchStoreStoreDist, PipelineBinaryCommands::geosearchStoreStoreDist, + destKey, key, param); + } + + return connection.invoke().just(Jedis::geosearchStore, PipelineBinaryCommands::geosearchStore, destKey, key, param); } } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java index 3da255e990..01310e1265 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java @@ -15,10 +15,10 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.MultiKeyPipelineBase; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.PipelineBinaryCommands; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; import java.util.ArrayList; import java.util.List; @@ -26,6 +26,7 @@ import java.util.Map.Entry; import java.util.Set; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisHashCommands; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.core.Cursor; @@ -55,7 +56,7 @@ public Boolean hSet(byte[] key, byte[] field, byte[] value) { Assert.notNull(field, "Field must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().from(BinaryJedis::hset, MultiKeyPipelineBase::hset, key, field, value) + return connection.invoke().from(Jedis::hset, PipelineBinaryCommands::hset, key, field, value) .get(JedisConverters.longToBoolean()); } @@ -66,7 +67,7 @@ public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { Assert.notNull(field, "Field must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().from(BinaryJedis::hsetnx, MultiKeyPipelineBase::hsetnx, key, field, value) + return connection.invoke().from(Jedis::hsetnx, PipelineBinaryCommands::hsetnx, key, field, value) .get(JedisConverters.longToBoolean()); } @@ -76,7 +77,7 @@ public Long hDel(byte[] key, byte[]... fields) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(fields, "Fields must not be null!"); - return connection.invoke().just(BinaryJedis::hdel, MultiKeyPipelineBase::hdel, key, fields); + return connection.invoke().just(Jedis::hdel, PipelineBinaryCommands::hdel, key, fields); } @Override @@ -85,7 +86,7 @@ public Boolean hExists(byte[] key, byte[] field) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Fields must not be null!"); - return connection.invoke().just(BinaryJedis::hexists, MultiKeyPipelineBase::hexists, key, field); + return connection.invoke().just(Jedis::hexists, PipelineBinaryCommands::hexists, key, field); } @Override @@ -94,7 +95,7 @@ public byte[] hGet(byte[] key, byte[] field) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - return connection.invoke().just(BinaryJedis::hget, MultiKeyPipelineBase::hget, key, field); + return connection.invoke().just(Jedis::hget, PipelineBinaryCommands::hget, key, field); } @Override @@ -102,7 +103,7 @@ public Map hGetAll(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::hgetAll, MultiKeyPipelineBase::hgetAll, key); + return connection.invoke().just(Jedis::hgetAll, PipelineBinaryCommands::hgetAll, key); } @Nullable @@ -111,7 +112,7 @@ public byte[] hRandField(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::hrandfield, MultiKeyPipelineBase::hrandfield, key); + return connection.invoke().just(Jedis::hrandfield, PipelineBinaryCommands::hrandfield, key); } @Nullable @@ -120,8 +121,7 @@ public Entry hRandFieldWithValues(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke() - .from(BinaryJedis::hrandfieldWithValues, MultiKeyPipelineBase::hrandfieldWithValues, key, 1L) + return connection.invoke().from(Jedis::hrandfieldWithValues, PipelineBinaryCommands::hrandfieldWithValues, key, 1L) .get(it -> it.isEmpty() ? null : it.entrySet().iterator().next()); } @@ -131,7 +131,7 @@ public List hRandField(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::hrandfield, MultiKeyPipelineBase::hrandfield, key, count); + return connection.invoke().just(Jedis::hrandfield, PipelineBinaryCommands::hrandfield, key, count); } @Nullable @@ -141,7 +141,7 @@ public List> hRandFieldWithValues(byte[] key, long count) Assert.notNull(key, "Key must not be null!"); return connection.invoke() - .from(BinaryJedis::hrandfieldWithValues, MultiKeyPipelineBase::hrandfieldWithValues, key, count).get(it -> { + .from(Jedis::hrandfieldWithValues, PipelineBinaryCommands::hrandfieldWithValues, key, count).get(it -> { List> entries = new ArrayList<>(it.size()); it.forEach((k, v) -> entries.add(Converters.entryOf(k, v))); @@ -156,7 +156,7 @@ public Long hIncrBy(byte[] key, byte[] field, long delta) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - return connection.invoke().just(BinaryJedis::hincrBy, MultiKeyPipelineBase::hincrBy, key, field, delta); + return connection.invoke().just(Jedis::hincrBy, PipelineBinaryCommands::hincrBy, key, field, delta); } @Override @@ -165,7 +165,7 @@ public Double hIncrBy(byte[] key, byte[] field, double delta) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - return connection.invoke().just(BinaryJedis::hincrByFloat, MultiKeyPipelineBase::hincrByFloat, key, field, delta); + return connection.invoke().just(Jedis::hincrByFloat, PipelineBinaryCommands::hincrByFloat, key, field, delta); } @Override @@ -173,7 +173,7 @@ public Set hKeys(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::hkeys, MultiKeyPipelineBase::hkeys, key); + return connection.invoke().just(Jedis::hkeys, PipelineBinaryCommands::hkeys, key); } @Override @@ -181,7 +181,7 @@ public Long hLen(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::hlen, MultiKeyPipelineBase::hlen, key); + return connection.invoke().just(Jedis::hlen, PipelineBinaryCommands::hlen, key); } @Override @@ -190,7 +190,7 @@ public List hMGet(byte[] key, byte[]... fields) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(fields, "Fields must not be null!"); - return connection.invoke().just(BinaryJedis::hmget, MultiKeyPipelineBase::hmget, key, fields); + return connection.invoke().just(Jedis::hmget, PipelineBinaryCommands::hmget, key, fields); } @Override @@ -199,7 +199,7 @@ public void hMSet(byte[] key, Map hashes) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(hashes, "Hashes must not be null!"); - connection.invokeStatus().just(BinaryJedis::hmset, MultiKeyPipelineBase::hmset, key, hashes); + connection.invokeStatus().just(Jedis::hmset, PipelineBinaryCommands::hmset, key, hashes); } @Override @@ -207,7 +207,7 @@ public List hVals(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::hvals, MultiKeyPipelineBase::hvals, key); + return connection.invoke().just(Jedis::hvals, PipelineBinaryCommands::hvals, key); } @Override @@ -232,7 +232,7 @@ public Cursor> hScan(byte[] key, long cursorId, ScanOption protected ScanIteration> doScan(byte[] key, long cursorId, ScanOptions options) { if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'HSCAN' cannot be called in pipeline / transaction mode."); } ScanParams params = JedisConverters.toScanParams(options); @@ -257,7 +257,7 @@ public Long hStrLen(byte[] key, byte[] field) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - return connection.invoke().just(BinaryJedis::hstrlen, MultiKeyPipelineBase::hstrlen, key, field); + return connection.invoke().just(Jedis::hstrlen, PipelineBinaryCommands::hstrlen, key, field); } private boolean isPipelined() { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java index a22f7e6c15..7be4620586 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java @@ -15,8 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.MultiKeyPipelineBase; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.PipelineBinaryCommands; import org.springframework.data.redis.connection.RedisHyperLogLogCommands; import org.springframework.util.Assert; @@ -40,7 +40,7 @@ public Long pfAdd(byte[] key, byte[]... values) { Assert.notEmpty(values, "PFADD requires at least one non 'null' value."); Assert.noNullElements(values, "Values for PFADD must not contain 'null'."); - return connection.invoke().just(BinaryJedis::pfadd, MultiKeyPipelineBase::pfadd, key, values); + return connection.invoke().just(Jedis::pfadd, PipelineBinaryCommands::pfadd, key, values); } @Override @@ -49,7 +49,7 @@ public Long pfCount(byte[]... keys) { Assert.notEmpty(keys, "PFCOUNT requires at least one non 'null' key."); Assert.noNullElements(keys, "Keys for PFCOUNT must not contain 'null'."); - return connection.invoke().just(BinaryJedis::pfcount, MultiKeyPipelineBase::pfcount, keys); + return connection.invoke().just(Jedis::pfcount, PipelineBinaryCommands::pfcount, keys); } @Override @@ -59,7 +59,7 @@ public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { Assert.notNull(sourceKeys, "Source keys must not be null"); Assert.noNullElements(sourceKeys, "Keys for PFMERGE must not contain 'null'."); - connection.invoke().just(BinaryJedis::pfmerge, MultiKeyPipelineBase::pfmerge, destinationKey, sourceKeys); + connection.invoke().just(Jedis::pfmerge, PipelineBinaryCommands::pfmerge, destinationKey, sourceKeys); } } 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 fcf160b504..a938766253 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 @@ -16,8 +16,12 @@ package org.springframework.data.redis.connection.jedis; import redis.clients.jedis.Jedis; -import redis.clients.jedis.MultiKeyPipelineBase; +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; +import redis.clients.jedis.commands.PipelineBinaryCommands; import java.util.ArrayList; import java.util.Collection; @@ -28,7 +32,9 @@ import java.util.function.Function; import java.util.function.Supplier; +import org.springframework.aop.framework.ProxyFactory; import org.springframework.core.convert.converter.Converter; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -77,7 +83,7 @@ R just(ConnectionFunction0 function) { Assert.notNull(function, "ConnectionFunction must not be null!"); return synchronizer.invoke(function::apply, it -> { - throw new UnsupportedOperationException("Operation not supported in pipelining/transaction mode"); + throw new InvalidDataAccessApiUsageException("Operation not supported by Jedis in pipelining/transaction mode"); }, Converters.identityConverter(), () -> null); } @@ -226,7 +232,7 @@ SingleInvocationSpec from(ConnectionFunction0 function) { Assert.notNull(function, "ConnectionFunction must not be null!"); return from(function, connection -> { - throw new UnsupportedOperationException("Operation not supported in pipelining/transaction mode"); + throw new InvalidDataAccessApiUsageException("Operation not supported in pipelining/transaction mode"); }); } @@ -374,7 +380,7 @@ , E> ManyInvocationSpec fromMany(ConnectionFunction0< Assert.notNull(function, "ConnectionFunction must not be null!"); return fromMany(function, connection -> { - throw new UnsupportedOperationException("Operation not supported in pipelining/transaction mode"); + throw new InvalidDataAccessApiUsageException("Operation not supported in pipelining/transaction mode"); }); } @@ -762,7 +768,7 @@ interface ConnectionFunction6 { } /** - * A function accepting {@link MultiKeyPipelineBase} with 0 arguments. + * A function accepting {@link ResponseCommands} with 0 arguments. * * @param */ @@ -774,11 +780,11 @@ interface PipelineFunction0 { * * @param connection the connection in use. Never {@literal null}. */ - Response apply(MultiKeyPipelineBase connection); + Response apply(ResponseCommands connection); } /** - * A function accepting {@link MultiKeyPipelineBase} with 1 argument. + * A function accepting {@link ResponseCommands} with 1 argument. * * @param * @param @@ -792,11 +798,11 @@ interface PipelineFunction1 { * @param connection the connection in use. Never {@literal null}. * @param t1 first argument. */ - Response apply(MultiKeyPipelineBase connection, T1 t1); + Response apply(ResponseCommands connection, T1 t1); } /** - * A function accepting {@link MultiKeyPipelineBase} with 2 arguments. + * A function accepting {@link ResponseCommands} with 2 arguments. * * @param * @param @@ -812,11 +818,11 @@ interface PipelineFunction2 { * @param t1 first argument. * @param t2 second argument. */ - Response apply(MultiKeyPipelineBase connection, T1 t1, T2 t2); + Response apply(ResponseCommands connection, T1 t1, T2 t2); } /** - * A function accepting {@link MultiKeyPipelineBase} with 3 arguments. + * A function accepting {@link ResponseCommands} with 3 arguments. * * @param * @param @@ -834,11 +840,11 @@ interface PipelineFunction3 { * @param t2 second argument. * @param t3 third argument. */ - Response apply(MultiKeyPipelineBase connection, T1 t1, T2 t2, T3 t3); + Response apply(ResponseCommands connection, T1 t1, T2 t2, T3 t3); } /** - * A function accepting {@link MultiKeyPipelineBase} with 4 arguments. + * A function accepting {@link ResponseCommands} with 4 arguments. * * @param * @param @@ -858,11 +864,11 @@ interface PipelineFunction4 { * @param t3 third argument. * @param t4 fourth argument. */ - Response apply(MultiKeyPipelineBase connection, T1 t1, T2 t2, T3 t3, T4 t4); + Response apply(ResponseCommands connection, T1 t1, T2 t2, T3 t3, T4 t4); } /** - * A function accepting {@link MultiKeyPipelineBase} with 5 arguments. + * A function accepting {@link ResponseCommands} with 5 arguments. * * @param * @param @@ -884,11 +890,11 @@ interface PipelineFunction5 { * @param t4 fourth argument. * @param t5 fifth argument. */ - Response apply(MultiKeyPipelineBase connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); + Response apply(ResponseCommands connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); } /** - * A function accepting {@link MultiKeyPipelineBase} with 6 arguments. + * A function accepting {@link ResponseCommands} with 6 arguments. * * @param * @param @@ -912,17 +918,17 @@ interface PipelineFunction6 { * @param t5 fifth argument. * @param t6 sixth argument. */ - Response apply(MultiKeyPipelineBase connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6); + Response apply(ResponseCommands connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6); } static class DefaultSingleInvocationSpec implements SingleInvocationSpec { private final Function parentFunction; - private final Function> parentPipelineFunction; + private final Function> parentPipelineFunction; private final Synchronizer synchronizer; DefaultSingleInvocationSpec(Function parentFunction, - Function> parentPipelineFunction, Synchronizer synchronizer) { + Function> parentPipelineFunction, Synchronizer synchronizer) { this.parentFunction = parentFunction; this.parentPipelineFunction = parentPipelineFunction; @@ -950,11 +956,11 @@ public T getOrElse(Converter converter, Supplier nullDefault) { static class DefaultManyInvocationSpec implements ManyInvocationSpec { private final Function> parentFunction; - private final Function>> parentPipelineFunction; + private final Function>> parentPipelineFunction; private final Synchronizer synchronizer; DefaultManyInvocationSpec(Function> parentFunction, - Function>> parentPipelineFunction, + Function>> parentPipelineFunction, Synchronizer synchronizer) { this.parentFunction = (Function) parentFunction; @@ -1013,24 +1019,42 @@ interface Synchronizer { @Nullable @SuppressWarnings({ "unchecked", "rawtypes" }) - default T invoke(Function callFunction, - Function> pipelineFunction) { - return (T) doInvoke((Function) callFunction, (Function) pipelineFunction, Converters.identityConverter(), () -> null); + default T invoke(Function callFunction, Function> pipelineFunction) { + return (T) doInvoke((Function) callFunction, (Function) pipelineFunction, Converters.identityConverter(), + () -> null); } @Nullable @SuppressWarnings({ "unchecked", "rawtypes" }) - default T invoke(Function callFunction, - Function> pipelineFunction, Converter converter, - Supplier nullDefault) { + default T invoke(Function callFunction, Function> pipelineFunction, + Converter converter, Supplier nullDefault) { return (T) doInvoke((Function) callFunction, (Function) pipelineFunction, (Converter) converter, (Supplier) nullDefault); } @Nullable - Object doInvoke(Function callFunction, - Function> pipelineFunction, Converter converter, - Supplier nullDefault); + Object doInvoke(Function callFunction, Function> pipelineFunction, + Converter converter, Supplier nullDefault); } + + interface ResponseCommands extends PipelineBinaryCommands, DatabasePipelineCommands { + + Response publish(String channel, String message); + } + + /** + * 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) { + + 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/JedisKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java index d12b07b5d7..1da8f99f6a 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 @@ -15,11 +15,12 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.MultiKeyPipelineBase; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; -import redis.clients.jedis.SortingParams; +import redis.clients.jedis.commands.JedisBinaryCommands; +import redis.clients.jedis.commands.PipelineBinaryCommands; +import redis.clients.jedis.params.RestoreParams; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.params.SortingParams; +import redis.clients.jedis.resps.ScanResult; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -27,6 +28,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.RedisKeyCommands; import org.springframework.data.redis.connection.SortParameters; @@ -61,7 +63,7 @@ public Boolean exists(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::exists, MultiKeyPipelineBase::exists, key); + return connection.invoke().just(JedisBinaryCommands::exists, PipelineBinaryCommands::exists, key); } @Nullable @@ -71,7 +73,7 @@ public Long exists(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::exists, MultiKeyPipelineBase::exists, keys); + return connection.invoke().just(JedisBinaryCommands::exists, PipelineBinaryCommands::exists, keys); } @Override @@ -80,7 +82,7 @@ public Long del(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::del, MultiKeyPipelineBase::del, keys); + return connection.invoke().just(JedisBinaryCommands::del, PipelineBinaryCommands::del, keys); } public Boolean copy(byte[] sourceKey, byte[] targetKey, boolean replace) { @@ -88,7 +90,8 @@ public Boolean copy(byte[] sourceKey, byte[] targetKey, boolean replace) { Assert.notNull(sourceKey, "source key must not be null!"); Assert.notNull(targetKey, "target key must not be null!"); - return connection.invoke().just(BinaryJedis::copy, MultiKeyPipelineBase::copy, sourceKey, targetKey, replace); + return connection.invoke().just(JedisBinaryCommands::copy, PipelineBinaryCommands::copy, sourceKey, targetKey, + replace); } @Nullable @@ -97,7 +100,7 @@ public Long unlink(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); - return connection.invoke().just(BinaryJedis::unlink, MultiKeyPipelineBase::unlink, keys); + return connection.invoke().just(JedisBinaryCommands::unlink, PipelineBinaryCommands::unlink, keys); } @Override @@ -105,7 +108,7 @@ public DataType type(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::type, MultiKeyPipelineBase::type, key) + return connection.invoke().from(JedisBinaryCommands::type, PipelineBinaryCommands::type, key) .get(JedisConverters.stringToDataType()); } @@ -115,7 +118,7 @@ public Long touch(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); - return connection.invoke().just(BinaryJedis::touch, MultiKeyPipelineBase::touch, keys); + return connection.invoke().just(JedisBinaryCommands::touch, PipelineBinaryCommands::touch, keys); } @Override @@ -123,7 +126,7 @@ public Set keys(byte[] pattern) { Assert.notNull(pattern, "Pattern must not be null!"); - return connection.invoke().just(BinaryJedis::keys, MultiKeyPipelineBase::keys, pattern); + return connection.invoke().just(JedisBinaryCommands::keys, PipelineBinaryCommands::keys, pattern); } @Override @@ -145,7 +148,7 @@ public Cursor scan(long cursorId, ScanOptions options) { protected ScanIteration doScan(long cursorId, ScanOptions options) { if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'SCAN' cannot be called in pipeline / transaction mode."); } ScanParams params = JedisConverters.toScanParams(options); @@ -164,12 +167,10 @@ protected ScanIteration doScan(long cursorId, ScanOptions options) { if (type != null) { result = connection.getJedis().scan(Long.toString(cursorId).getBytes(), params, type); } else { - result = connection.getJedis().scan(Long.toString(cursorId).getBytes(), - params); + result = connection.getJedis().scan(Long.toString(cursorId).getBytes(), params); } - return new ScanIteration<>(Long.parseLong(result.getCursor()), - result.getResult()); + return new ScanIteration<>(Long.parseLong(result.getCursor()), result.getResult()); } protected void doClose() { @@ -180,7 +181,7 @@ protected void doClose() { @Override public byte[] randomKey() { - return connection.invoke().just(BinaryJedis::randomBinaryKey, MultiKeyPipelineBase::randomKeyBinary); + return connection.invoke().just(JedisBinaryCommands::randomBinaryKey, PipelineBinaryCommands::randomBinaryKey); } @Override @@ -189,7 +190,7 @@ public void rename(byte[] oldKey, byte[] newKey) { Assert.notNull(oldKey, "Old key must not be null!"); Assert.notNull(newKey, "New key must not be null!"); - connection.invokeStatus().just(BinaryJedis::rename, MultiKeyPipelineBase::rename, oldKey, newKey); + connection.invokeStatus().just(JedisBinaryCommands::rename, PipelineBinaryCommands::rename, oldKey, newKey); } @Override @@ -198,7 +199,8 @@ public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { Assert.notNull(sourceKey, "Source key must not be null!"); Assert.notNull(targetKey, "Target key must not be null!"); - return connection.invoke().from(BinaryJedis::renamenx, MultiKeyPipelineBase::renamenx, sourceKey, targetKey) + return connection.invoke() + .from(JedisBinaryCommands::renamenx, PipelineBinaryCommands::renamenx, sourceKey, targetKey) .get(JedisConverters.longToBoolean()); } @@ -211,7 +213,7 @@ public Boolean expire(byte[] key, long seconds) { return pExpire(key, TimeUnit.SECONDS.toMillis(seconds)); } - return connection.invoke().from(BinaryJedis::expire, MultiKeyPipelineBase::expire, key, (int) seconds) + return connection.invoke().from(JedisBinaryCommands::expire, PipelineBinaryCommands::expire, key, seconds) .get(JedisConverters.longToBoolean()); } @@ -220,7 +222,7 @@ public Boolean pExpire(byte[] key, long millis) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::pexpire, MultiKeyPipelineBase::pexpire, key, millis) + return connection.invoke().from(JedisBinaryCommands::pexpire, PipelineBinaryCommands::pexpire, key, millis) .get(JedisConverters.longToBoolean()); } @@ -229,7 +231,7 @@ public Boolean expireAt(byte[] key, long unixTime) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::expireAt, MultiKeyPipelineBase::expireAt, key, unixTime) + return connection.invoke().from(JedisBinaryCommands::expireAt, PipelineBinaryCommands::expireAt, key, unixTime) .get(JedisConverters.longToBoolean()); } @@ -238,7 +240,8 @@ public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::pexpireAt, MultiKeyPipelineBase::pexpireAt, key, unixTimeInMillis) + return connection.invoke() + .from(JedisBinaryCommands::pexpireAt, PipelineBinaryCommands::pexpireAt, key, unixTimeInMillis) .get(JedisConverters.longToBoolean()); } @@ -247,7 +250,7 @@ public Boolean persist(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::persist, MultiKeyPipelineBase::persist, key) + return connection.invoke().from(JedisBinaryCommands::persist, PipelineBinaryCommands::persist, key) .get(JedisConverters.longToBoolean()); } @@ -256,8 +259,7 @@ public Boolean move(byte[] key, int dbIndex) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::move, MultiKeyPipelineBase::move, key, dbIndex) - .get(JedisConverters.longToBoolean()); + return connection.invoke().from(j -> j.move(key, dbIndex)).get(JedisConverters.longToBoolean()); } @Override @@ -265,7 +267,7 @@ public Long ttl(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::ttl, MultiKeyPipelineBase::ttl, key); + return connection.invoke().just(JedisBinaryCommands::ttl, PipelineBinaryCommands::ttl, key); } @Override @@ -273,7 +275,7 @@ public Long ttl(byte[] key, TimeUnit timeUnit) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::ttl, MultiKeyPipelineBase::ttl, key) + return connection.invoke().from(JedisBinaryCommands::ttl, PipelineBinaryCommands::ttl, key) .get(Converters.secondsToTimeUnit(timeUnit)); } @@ -282,7 +284,7 @@ public Long pTtl(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::pttl, MultiKeyPipelineBase::pttl, key); + return connection.invoke().just(JedisBinaryCommands::pttl, PipelineBinaryCommands::pttl, key); } @Override @@ -290,7 +292,7 @@ public Long pTtl(byte[] key, TimeUnit timeUnit) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::pttl, MultiKeyPipelineBase::pttl, key) + return connection.invoke().from(JedisBinaryCommands::pttl, PipelineBinaryCommands::pttl, key) .get(Converters.millisecondsToTimeUnit(timeUnit)); } @@ -302,10 +304,10 @@ public List sort(byte[] key, SortParameters params) { SortingParams sortParams = JedisConverters.toSortingParams(params); if (sortParams != null) { - return connection.invoke().just(BinaryJedis::sort, MultiKeyPipelineBase::sort, key, sortParams); + return connection.invoke().just(JedisBinaryCommands::sort, PipelineBinaryCommands::sort, key, sortParams); } - return connection.invoke().just(BinaryJedis::sort, MultiKeyPipelineBase::sort, key); + return connection.invoke().just(JedisBinaryCommands::sort, PipelineBinaryCommands::sort, key); } @Override @@ -316,10 +318,11 @@ public Long sort(byte[] key, @Nullable SortParameters params, byte[] storeKey) { SortingParams sortParams = JedisConverters.toSortingParams(params); if (sortParams != null) { - return connection.invoke().just(BinaryJedis::sort, MultiKeyPipelineBase::sort, key, sortParams, storeKey); + return connection.invoke().just(JedisBinaryCommands::sort, PipelineBinaryCommands::sort, key, sortParams, + storeKey); } - return connection.invoke().just(BinaryJedis::sort, MultiKeyPipelineBase::sort, key, storeKey); + return connection.invoke().just(JedisBinaryCommands::sort, PipelineBinaryCommands::sort, key, storeKey); } @Override @@ -327,7 +330,7 @@ public byte[] dump(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::dump, MultiKeyPipelineBase::dump, key); + return connection.invoke().just(JedisBinaryCommands::dump, PipelineBinaryCommands::dump, key); } @Override @@ -338,8 +341,8 @@ public void restore(byte[] key, long ttlInMillis, byte[] serializedValue, boolea if (replace) { - connection.invokeStatus().just(BinaryJedis::restoreReplace, MultiKeyPipelineBase::restoreReplace, key, - (int) ttlInMillis, serializedValue); + connection.invokeStatus().just(JedisBinaryCommands::restore, PipelineBinaryCommands::restore, key, + (int) ttlInMillis, serializedValue, RestoreParams.restoreParams().replace()); return; } @@ -347,8 +350,8 @@ public void restore(byte[] key, long ttlInMillis, byte[] serializedValue, boolea throw new IllegalArgumentException("TtlInMillis must be less than Integer.MAX_VALUE for restore in Jedis."); } - connection.invokeStatus().just(BinaryJedis::restore, MultiKeyPipelineBase::restore, key, (int) ttlInMillis, - serializedValue); + connection.invokeStatus().just(JedisBinaryCommands::restore, PipelineBinaryCommands::restore, key, + (int) ttlInMillis, serializedValue); } @Nullable @@ -357,7 +360,7 @@ public ValueEncoding encodingOf(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::objectEncoding, MultiKeyPipelineBase::objectEncoding, key) + return connection.invoke().from(JedisBinaryCommands::objectEncoding, PipelineBinaryCommands::objectEncoding, key) .getOrElse(JedisConverters::toEncoding, () -> RedisValueEncoding.VACANT); } @@ -367,7 +370,7 @@ public Duration idletime(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::objectIdletime, MultiKeyPipelineBase::objectIdletime, key) + return connection.invoke().from(JedisBinaryCommands::objectIdletime, PipelineBinaryCommands::objectIdletime, key) .get(Converters::secondsToDuration); } @@ -377,7 +380,7 @@ public Long refcount(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::objectRefcount, MultiKeyPipelineBase::objectRefcount, key); + return connection.invoke().just(JedisBinaryCommands::objectRefcount, PipelineBinaryCommands::objectRefcount, key); } private boolean isPipelined() { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java index 83b9c94b85..70bf4d5b92 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java @@ -15,10 +15,9 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.MultiKeyPipelineBase; -import redis.clients.jedis.Protocol; import redis.clients.jedis.args.ListDirection; +import redis.clients.jedis.commands.JedisBinaryCommands; +import redis.clients.jedis.commands.PipelineBinaryCommands; import redis.clients.jedis.params.LPosParams; import java.util.Collections; @@ -47,7 +46,7 @@ public Long rPush(byte[] key, byte[]... values) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::rpush, MultiKeyPipelineBase::rpush, key, values); + return connection.invoke().just(JedisBinaryCommands::rpush, PipelineBinaryCommands::rpush, key, values); } @Override @@ -62,10 +61,11 @@ public List lPos(byte[] key, byte[] element, @Nullable Integer rank, @Null } if (count != null) { - return connection.invoke().just(BinaryJedis::lpos, MultiKeyPipelineBase::lpos, key, element, params, count); + return connection.invoke().just(JedisBinaryCommands::lpos, PipelineBinaryCommands::lpos, key, element, params, + count); } - return connection.invoke().from(BinaryJedis::lpos, MultiKeyPipelineBase::lpos, key, element, params) + return connection.invoke().from(JedisBinaryCommands::lpos, PipelineBinaryCommands::lpos, key, element, params) .getOrElse(Collections::singletonList, Collections::emptyList); } @@ -76,7 +76,7 @@ public Long lPush(byte[] key, byte[]... values) { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - return connection.invoke().just(BinaryJedis::lpush, MultiKeyPipelineBase::lpush, key, values); + return connection.invoke().just(JedisBinaryCommands::lpush, PipelineBinaryCommands::lpush, key, values); } @Override @@ -85,7 +85,7 @@ public Long rPushX(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::rpushx, MultiKeyPipelineBase::rpushx, key, value); + return connection.invoke().just(JedisBinaryCommands::rpushx, PipelineBinaryCommands::rpushx, key, value); } @Override @@ -94,7 +94,7 @@ public Long lPushX(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::lpushx, MultiKeyPipelineBase::lpushx, key, value); + return connection.invoke().just(JedisBinaryCommands::lpushx, PipelineBinaryCommands::lpushx, key, value); } @Override @@ -102,7 +102,7 @@ public Long lLen(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::llen, MultiKeyPipelineBase::llen, key); + return connection.invoke().just(JedisBinaryCommands::llen, PipelineBinaryCommands::llen, key); } @Override @@ -110,7 +110,7 @@ public List lRange(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::lrange, MultiKeyPipelineBase::lrange, key, start, end); + return connection.invoke().just(JedisBinaryCommands::lrange, PipelineBinaryCommands::lrange, key, start, end); } @Override @@ -118,7 +118,7 @@ public void lTrim(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - connection.invokeStatus().just(BinaryJedis::ltrim, MultiKeyPipelineBase::ltrim, key, start, end); + connection.invokeStatus().just(JedisBinaryCommands::ltrim, PipelineBinaryCommands::ltrim, key, start, end); } @Override @@ -126,7 +126,7 @@ public byte[] lIndex(byte[] key, long index) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::lindex, MultiKeyPipelineBase::lindex, key, index); + return connection.invoke().just(JedisBinaryCommands::lindex, PipelineBinaryCommands::lindex, key, index); } @Override @@ -134,7 +134,7 @@ public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::linsert, MultiKeyPipelineBase::linsert, key, + return connection.invoke().just(JedisBinaryCommands::linsert, PipelineBinaryCommands::linsert, key, JedisConverters.toListPosition(where), pivot, value); } @@ -146,8 +146,8 @@ public byte[] lMove(byte[] sourceKey, byte[] destinationKey, Direction from, Dir Assert.notNull(from, "From direction must not be null!"); Assert.notNull(to, "To direction must not be null!"); - return connection.invoke().just(BinaryJedis::lmove, MultiKeyPipelineBase::lmove, sourceKey, destinationKey, - ListDirection.valueOf(from.name()), ListDirection.valueOf(to.name())); + return connection.invoke().just(JedisBinaryCommands::lmove, PipelineBinaryCommands::lmove, sourceKey, + destinationKey, ListDirection.valueOf(from.name()), ListDirection.valueOf(to.name())); } @Override @@ -158,8 +158,8 @@ public byte[] bLMove(byte[] sourceKey, byte[] destinationKey, Direction from, Di Assert.notNull(from, "From direction must not be null!"); Assert.notNull(to, "To direction must not be null!"); - return connection.invoke().just(BinaryJedis::blmove, MultiKeyPipelineBase::blmove, sourceKey, destinationKey, - ListDirection.valueOf(from.name()), ListDirection.valueOf(to.name()), timeout); + return connection.invoke().just(JedisBinaryCommands::blmove, PipelineBinaryCommands::blmove, sourceKey, + destinationKey, ListDirection.valueOf(from.name()), ListDirection.valueOf(to.name()), timeout); } @Override @@ -168,7 +168,7 @@ public void lSet(byte[] key, long index, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - connection.invokeStatus().just(BinaryJedis::lset, MultiKeyPipelineBase::lset, key, index, value); + connection.invokeStatus().just(JedisBinaryCommands::lset, PipelineBinaryCommands::lset, key, index, value); } @Override @@ -177,7 +177,7 @@ public Long lRem(byte[] key, long count, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::lrem, MultiKeyPipelineBase::lrem, key, count, value); + return connection.invoke().just(JedisBinaryCommands::lrem, PipelineBinaryCommands::lrem, key, count, value); } @Override @@ -185,7 +185,7 @@ public byte[] lPop(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::lpop, MultiKeyPipelineBase::lpop, key); + return connection.invoke().just(JedisBinaryCommands::lpop, PipelineBinaryCommands::lpop, key); } @Override @@ -193,7 +193,7 @@ public List lPop(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::lpop, MultiKeyPipelineBase::lpop, key, (int) count); + return connection.invoke().just(JedisBinaryCommands::lpop, PipelineBinaryCommands::lpop, key, (int) count); } @Override @@ -201,7 +201,7 @@ public byte[] rPop(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::rpop, MultiKeyPipelineBase::rpop, key); + return connection.invoke().just(JedisBinaryCommands::rpop, PipelineBinaryCommands::rpop, key); } @Override @@ -209,7 +209,7 @@ public List rPop(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::rpop, MultiKeyPipelineBase::rpop, key, (int) count); + return connection.invoke().just(JedisBinaryCommands::rpop, PipelineBinaryCommands::rpop, key, (int) count); } @Override @@ -218,7 +218,7 @@ public List bLPop(int timeout, byte[]... keys) { Assert.notNull(keys, "Key must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::blpop, MultiKeyPipelineBase::blpop, bXPopArgs(timeout, keys)); + return connection.invoke().just(j -> j.blpop(timeout, keys), j -> j.blpop(timeout, keys)); } @Override @@ -227,7 +227,7 @@ public List bRPop(int timeout, byte[]... keys) { Assert.notNull(keys, "Key must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::brpop, MultiKeyPipelineBase::brpop, bXPopArgs(timeout, keys)); + return connection.invoke().just(j -> j.brpop(timeout, keys), j -> j.brpop(timeout, keys)); } @Override @@ -236,7 +236,7 @@ public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { Assert.notNull(srcKey, "Source key must not be null!"); Assert.notNull(dstKey, "Destination key must not be null!"); - return connection.invoke().just(BinaryJedis::rpoplpush, MultiKeyPipelineBase::rpoplpush, srcKey, dstKey); + return connection.invoke().just(JedisBinaryCommands::rpoplpush, PipelineBinaryCommands::rpoplpush, srcKey, dstKey); } @Override @@ -245,16 +245,8 @@ public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { Assert.notNull(srcKey, "Source key must not be null!"); Assert.notNull(dstKey, "Destination key must not be null!"); - return connection.invoke().just(BinaryJedis::brpoplpush, MultiKeyPipelineBase::brpoplpush, srcKey, dstKey, timeout); - } - - private static byte[][] bXPopArgs(int timeout, byte[]... keys) { - - byte[][] args = new byte[keys.length + 1][]; - System.arraycopy(keys, 0, args, 0, keys.length); - - args[args.length - 1] = Protocol.toByteArray(timeout); - return args; + return connection.invoke().just(JedisBinaryCommands::brpoplpush, PipelineBinaryCommands::brpoplpush, srcKey, dstKey, + timeout); } } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java index ba9026568e..4d1f8a6b60 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java @@ -15,10 +15,11 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; +import redis.clients.jedis.Jedis; import java.util.List; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisScriptingCommands; import org.springframework.data.redis.connection.ReturnType; import org.springframework.util.Assert; @@ -40,7 +41,7 @@ public void scriptFlush() { assertDirectMode(); - connection.invoke().just(BinaryJedis::scriptFlush); + connection.invoke().just(Jedis::scriptFlush); } @Override @@ -48,7 +49,7 @@ public void scriptKill() { assertDirectMode(); - connection.invoke().just(BinaryJedis::scriptKill); + connection.invoke().just(Jedis::scriptKill); } @Override @@ -78,8 +79,8 @@ public T eval(byte[] script, ReturnType returnType, int numKeys, byte[]... k assertDirectMode(); JedisScriptReturnConverter converter = new JedisScriptReturnConverter(returnType); - return (T) connection.invoke().from(it -> it.eval(script, JedisConverters.toBytes(numKeys), keysAndArgs)) - .getOrElse(converter, () -> converter.convert(null)); + return (T) connection.invoke().from(it -> it.eval(script, numKeys, keysAndArgs)).getOrElse(converter, + () -> converter.convert(null)); } @Override @@ -101,7 +102,7 @@ public T evalSha(byte[] scriptSha, ReturnType returnType, int numKeys, byte[ private void assertDirectMode() { if (connection.isQueueing() || connection.isPipelined()) { - throw new UnsupportedOperationException("Scripting commands not supported in pipelining/transaction mode"); + throw new InvalidDataAccessApiUsageException("Scripting commands not supported in pipelining/transaction mode"); } } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisServerCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisServerCommands.java index 078cccd6c2..de0547b8f6 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisServerCommands.java @@ -15,9 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; import redis.clients.jedis.Jedis; -import redis.clients.jedis.MultiKeyPipelineBase; import redis.clients.jedis.args.SaveMode; import java.util.List; @@ -46,54 +44,52 @@ class JedisServerCommands implements RedisServerCommands { @Override public void bgReWriteAof() { - connection.invoke().just(BinaryJedis::bgrewriteaof, MultiKeyPipelineBase::bgrewriteaof); + connection.invoke().just(Jedis::bgrewriteaof); } @Override public void bgSave() { - connection.invokeStatus().just(BinaryJedis::bgsave, MultiKeyPipelineBase::bgsave); + connection.invokeStatus().just(Jedis::bgsave); } @Override public Long lastSave() { - return connection.invoke().just(BinaryJedis::lastsave, MultiKeyPipelineBase::lastsave); + return connection.invoke().just(Jedis::lastsave); } @Override public void save() { - connection.invokeStatus().just(BinaryJedis::save, MultiKeyPipelineBase::save); + connection.invokeStatus().just(Jedis::save); } @Override public Long dbSize() { - return connection.invoke().just(BinaryJedis::dbSize, MultiKeyPipelineBase::dbSize); + return connection.invoke().just(Jedis::dbSize); } @Override public void flushDb() { - connection.invokeStatus().just(BinaryJedis::flushDB, MultiKeyPipelineBase::flushDB); + connection.invokeStatus().just(Jedis::flushDB); } @Override public void flushDb(FlushOption option) { - connection.invokeStatus().just(BinaryJedis::flushDB, MultiKeyPipelineBase::flushDB, - JedisConverters.toFlushMode(option)); + connection.invokeStatus().just(j -> j.flushDB(JedisConverters.toFlushMode(option))); } @Override public void flushAll() { - connection.invokeStatus().just(BinaryJedis::flushAll, MultiKeyPipelineBase::flushAll); + connection.invokeStatus().just(Jedis::flushAll); } @Override public void flushAll(FlushOption option) { - connection.invokeStatus().just(BinaryJedis::flushAll, MultiKeyPipelineBase::flushAll, - JedisConverters.toFlushMode(option)); + connection.invokeStatus().just(j -> j.flushAll(JedisConverters.toFlushMode(option))); } @Override public Properties info() { - return connection.invoke().from(BinaryJedis::info, MultiKeyPipelineBase::info).get(JedisConverters::toProperties); + return connection.invoke().from(Jedis::info).get(JedisConverters::toProperties); } @Override @@ -101,13 +97,15 @@ public Properties info(String section) { Assert.notNull(section, "Section must not be null!"); - return connection.invoke().from(BinaryJedis::info, MultiKeyPipelineBase::info, section) - .get(JedisConverters::toProperties); + return connection.invoke().from(j -> j.info(section)).get(JedisConverters::toProperties); } @Override public void shutdown() { - connection.invokeStatus().just(BinaryJedis::shutdown, MultiKeyPipelineBase::shutdown); + connection.invokeStatus().just(jedis -> { + jedis.shutdown(); + return null; + }); } @Override @@ -128,8 +126,7 @@ public Properties getConfig(String pattern) { Assert.notNull(pattern, "Pattern must not be null!"); - return connection.invoke().from(Jedis::configGet, MultiKeyPipelineBase::configGet, pattern) - .get(Converters::toProperties); + return connection.invoke().from(j -> j.configGet(pattern)).get(Converters::toProperties); } @Override @@ -138,12 +135,12 @@ public void setConfig(String param, String value) { Assert.notNull(param, "Parameter must not be null!"); Assert.notNull(value, "Value must not be null!"); - connection.invokeStatus().just(Jedis::configSet, MultiKeyPipelineBase::configSet, param, value); + connection.invokeStatus().just(j -> j.configSet(param, value)); } @Override public void resetConfigStats() { - connection.invokeStatus().just(BinaryJedis::configResetStat, MultiKeyPipelineBase::configResetStat); + connection.invokeStatus().just(Jedis::configResetStat); } @Override @@ -156,8 +153,7 @@ public Long time(TimeUnit timeUnit) { Assert.notNull(timeUnit, "TimeUnit must not be null."); - return connection.invoke().from(BinaryJedis::time, MultiKeyPipelineBase::time) - .get((List source) -> JedisConverters.toTime(source, timeUnit)); + return connection.invoke().from(Jedis::time).get((List source) -> JedisConverters.toTime(source, timeUnit)); } @Override @@ -165,10 +161,6 @@ public void killClient(String host, int port) { Assert.hasText(host, "Host for 'CLIENT KILL' must not be 'null' or 'empty'."); - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'CLIENT KILL' is not supported in transaction / pipline mode."); - } - connection.invokeStatus().just(it -> it.clientKill(String.format("%s:%s", host, port))); } @@ -177,30 +169,16 @@ public void setClientName(byte[] name) { Assert.notNull(name, "Name must not be null!"); - if (isPipelined() || isQueueing()) { - throw new UnsupportedOperationException("'CLIENT SETNAME' is not suppored in transacton / pipeline mode."); - } - connection.invokeStatus().just(it -> it.clientSetname(name)); } @Override public String getClientName() { - - if (isPipelined() || isQueueing()) { - throw new UnsupportedOperationException(); - } - return connection.invokeStatus().just(Jedis::clientGetname); } @Override public List getClientList() { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'CLIENT LIST' is not supported in in pipeline / multi mode."); - } - return connection.invokeStatus().from(Jedis::clientList).get(JedisConverters::toListOfRedisClientInformation); } @@ -209,21 +187,12 @@ public void replicaOf(String host, int port) { Assert.hasText(host, "Host must not be null for 'REPLICAOF' command."); - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'REPLICAOF' cannot be called in pipeline / transaction mode."); - } - - connection.invokeStatus().just(it -> it.slaveof(host, port)); + connection.invokeStatus().just(it -> it.replicaof(host, port)); } @Override public void replicaOfNoOne() { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'REPLICAOF' cannot be called in pipeline / transaction mode."); - } - - connection.invokeStatus().just(BinaryJedis::slaveofNoOne); + connection.invokeStatus().just(Jedis::replicaofNoOne); } @Override @@ -239,16 +208,7 @@ public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable Migrate int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; - connection.invokeStatus().just(BinaryJedis::migrate, MultiKeyPipelineBase::migrate, target.getHost(), - target.getPort(), key, dbIndex, timeoutToUse); - } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); + connection.invokeStatus().just(j -> j.migrate(target.getHost(), target.getPort(), key, dbIndex, timeoutToUse)); } } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java index cb9fc7b8c3..4d0452bcaa 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java @@ -15,14 +15,16 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.MultiKeyPipelineBase; -import redis.clients.jedis.ScanParams; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.PipelineBinaryCommands; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; import java.util.ArrayList; import java.util.List; import java.util.Set; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisSetCommands; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; @@ -50,7 +52,7 @@ public Long sAdd(byte[] key, byte[]... values) { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - return connection.invoke().just(BinaryJedis::sadd, MultiKeyPipelineBase::sadd, key, values); + return connection.invoke().just(Jedis::sadd, PipelineBinaryCommands::sadd, key, values); } @Override @@ -58,7 +60,7 @@ public Long sCard(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::scard, MultiKeyPipelineBase::scard, key); + return connection.invoke().just(Jedis::scard, PipelineBinaryCommands::scard, key); } @Override @@ -67,7 +69,7 @@ public Set sDiff(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::sdiff, MultiKeyPipelineBase::sdiff, keys); + return connection.invoke().just(Jedis::sdiff, PipelineBinaryCommands::sdiff, keys); } @Override @@ -77,7 +79,7 @@ public Long sDiffStore(byte[] destKey, byte[]... keys) { Assert.notNull(keys, "Source keys must not be null!"); Assert.noNullElements(keys, "Source keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::sdiffstore, MultiKeyPipelineBase::sdiffstore, destKey, keys); + return connection.invoke().just(Jedis::sdiffstore, PipelineBinaryCommands::sdiffstore, destKey, keys); } @Override @@ -86,7 +88,7 @@ public Set sInter(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::sinter, MultiKeyPipelineBase::sinter, keys); + return connection.invoke().just(Jedis::sinter, PipelineBinaryCommands::sinter, keys); } @Override @@ -96,7 +98,7 @@ public Long sInterStore(byte[] destKey, byte[]... keys) { Assert.notNull(keys, "Source keys must not be null!"); Assert.noNullElements(keys, "Source keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::sinterstore, MultiKeyPipelineBase::sinterstore, destKey, keys); + return connection.invoke().just(Jedis::sinterstore, PipelineBinaryCommands::sinterstore, destKey, keys); } @Override @@ -105,7 +107,7 @@ public Boolean sIsMember(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::sismember, MultiKeyPipelineBase::sismember, key, value); + return connection.invoke().just(Jedis::sismember, PipelineBinaryCommands::sismember, key, value); } @Override @@ -115,7 +117,7 @@ public List sMIsMember(byte[] key, byte[]... values) { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - return connection.invoke().just(BinaryJedis::smismember, MultiKeyPipelineBase::smismember, key, values); + return connection.invoke().just(Jedis::smismember, PipelineBinaryCommands::smismember, key, values); } @Override @@ -123,7 +125,7 @@ public Set sMembers(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::smembers, MultiKeyPipelineBase::smembers, key); + return connection.invoke().just(Jedis::smembers, PipelineBinaryCommands::smembers, key); } @Override @@ -133,7 +135,7 @@ public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { Assert.notNull(destKey, "Destination key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().from(BinaryJedis::smove, MultiKeyPipelineBase::smove, srcKey, destKey, value) + return connection.invoke().from(Jedis::smove, PipelineBinaryCommands::smove, srcKey, destKey, value) .get(JedisConverters::toBoolean); } @@ -142,7 +144,7 @@ public byte[] sPop(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::spop, MultiKeyPipelineBase::spop, key); + return connection.invoke().just(Jedis::spop, PipelineBinaryCommands::spop, key); } @Override @@ -150,7 +152,7 @@ public List sPop(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::spop, MultiKeyPipelineBase::spop, key, count).get(ArrayList::new); + return connection.invoke().from(Jedis::spop, PipelineBinaryCommands::spop, key, count).get(ArrayList::new); } @Override @@ -158,7 +160,7 @@ public byte[] sRandMember(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::srandmember, MultiKeyPipelineBase::srandmember, key); + return connection.invoke().just(Jedis::srandmember, PipelineBinaryCommands::srandmember, key); } @Override @@ -170,7 +172,7 @@ public List sRandMember(byte[] key, long count) { throw new IllegalArgumentException("Count must be less than Integer.MAX_VALUE for sRandMember in Jedis."); } - return connection.invoke().just(BinaryJedis::srandmember, MultiKeyPipelineBase::srandmember, key, (int) count); + return connection.invoke().just(Jedis::srandmember, PipelineBinaryCommands::srandmember, key, (int) count); } @Override @@ -180,7 +182,7 @@ public Long sRem(byte[] key, byte[]... values) { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - return connection.invoke().just(BinaryJedis::srem, MultiKeyPipelineBase::srem, key, values); + return connection.invoke().just(Jedis::srem, PipelineBinaryCommands::srem, key, values); } @Override @@ -189,7 +191,7 @@ public Set sUnion(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::sunion, MultiKeyPipelineBase::sunion, keys); + return connection.invoke().just(Jedis::sunion, PipelineBinaryCommands::sunion, keys); } @Override @@ -199,7 +201,7 @@ public Long sUnionStore(byte[] destKey, byte[]... keys) { Assert.notNull(keys, "Source keys must not be null!"); Assert.noNullElements(keys, "Source keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::sunionstore, MultiKeyPipelineBase::sunionstore, destKey, keys); + return connection.invoke().just(Jedis::sunionstore, PipelineBinaryCommands::sunionstore, destKey, keys); } @Override @@ -224,13 +226,12 @@ public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'SSCAN' cannot be called in pipeline / transaction mode."); } ScanParams params = JedisConverters.toScanParams(options); - redis.clients.jedis.ScanResult result = connection.getJedis().sscan(key, - JedisConverters.toBytes(cursorId), params); + ScanResult result = connection.getJedis().sscan(key, JedisConverters.toBytes(cursorId), params); return new ScanIteration<>(Long.valueOf(result.getCursor()), result.getResult()); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStreamCommands.java index b176b6f116..c08d63a534 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStreamCommands.java @@ -15,12 +15,17 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; import redis.clients.jedis.BuilderFactory; -import redis.clients.jedis.MultiKeyPipelineBase; -import redis.clients.jedis.StreamConsumersInfo; -import redis.clients.jedis.StreamGroupInfo; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.PipelineBinaryCommands; +import redis.clients.jedis.commands.StreamPipelineBinaryCommands; import redis.clients.jedis.params.XAddParams; +import redis.clients.jedis.params.XClaimParams; +import redis.clients.jedis.params.XPendingParams; +import redis.clients.jedis.params.XReadGroupParams; +import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.resps.StreamConsumersInfo; +import redis.clients.jedis.resps.StreamGroupInfo; import java.util.ArrayList; import java.util.Arrays; @@ -30,6 +35,7 @@ import org.springframework.data.domain.Range; import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisStreamCommands; +import org.springframework.data.redis.connection.jedis.JedisInvoker.ResponseCommands; import org.springframework.data.redis.connection.stream.ByteRecord; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; @@ -61,7 +67,7 @@ public Long xAck(byte[] key, String group, RecordId... recordIds) { Assert.hasText(group, "Group name must not be null or empty!"); Assert.notNull(recordIds, "recordIds must not be null!"); - return connection.invoke().just(BinaryJedis::xack, MultiKeyPipelineBase::xack, key, JedisConverters.toBytes(group), + return connection.invoke().just(Jedis::xack, PipelineBinaryCommands::xack, key, JedisConverters.toBytes(group), StreamConverters.entryIdsToBytes(Arrays.asList(recordIds))); } @@ -71,16 +77,27 @@ public RecordId xAdd(MapRecord record, XAddOptions optio Assert.notNull(record, "Record must not be null!"); Assert.notNull(record.getStream(), "Stream must not be null!"); - XAddParams params = StreamConverters.toXAddParams(record, options); + XAddParams params = StreamConverters.toXAddParams(record.getId(), options); return connection.invoke() - .from(BinaryJedis::xadd, MultiKeyPipelineBase::xadd, record.getStream(), record.getValue(), params) + .from(Jedis::xadd, PipelineBinaryCommands::xadd, record.getStream(), record.getValue(), params) .get(it -> RecordId.of(JedisConverters.toString(it))); } @Override public List xClaimJustId(byte[] key, String group, String newOwner, XClaimOptions options) { - throw new UnsupportedOperationException("Jedis does not support xClaimJustId."); + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(group, "Group must not be null!"); + Assert.notNull(newOwner, "NewOwner must not be null!"); + + XClaimParams params = StreamConverters.toXClaimParams(options); + + return connection.invoke() + .fromMany(Jedis::xclaimJustId, ResponseCommands::xclaimJustId, key, JedisConverters.toBytes(group), + JedisConverters.toBytes(newOwner), options.getMinIdleTime().toMillis(), params, + StreamConverters.entryIdsToBytes(options.getIds())) + .toList(it -> RecordId.of(JedisConverters.toString(it))); } @Override @@ -90,16 +107,12 @@ public List xClaim(byte[] key, String group, String newOwner, XClaim Assert.notNull(group, "Group must not be null!"); Assert.notNull(newOwner, "NewOwner must not be null!"); - long minIdleTime = options.getMinIdleTime() == null ? -1L : options.getMinIdleTime().toMillis(); - int retryCount = options.getRetryCount() == null ? -1 : options.getRetryCount().intValue(); - long unixTime = options.getUnixTime() == null ? -1L : options.getUnixTime().toEpochMilli(); + XClaimParams params = StreamConverters.toXClaimParams(options); return connection.invoke() - .from( - it -> it.xclaim(key, JedisConverters.toBytes(group), JedisConverters.toBytes(newOwner), minIdleTime, - unixTime, retryCount, options.isForce(), StreamConverters.entryIdsToBytes(options.getIds())), - it -> it.xclaim(key, JedisConverters.toBytes(group), JedisConverters.toBytes(newOwner), minIdleTime, - unixTime, retryCount, options.isForce(), StreamConverters.entryIdsToBytes(options.getIds()))) + .from(Jedis::xclaim, ResponseCommands::xclaim, key, JedisConverters.toBytes(group), + JedisConverters.toBytes(newOwner), options.getMinIdleTime().toMillis(), params, + StreamConverters.entryIdsToBytes(options.getIds())) .get(r -> StreamConverters.convertToByteRecord(key, r)); } @@ -109,7 +122,7 @@ public Long xDel(byte[] key, RecordId... recordIds) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(recordIds, "recordIds must not be null!"); - return connection.invoke().just(BinaryJedis::xdel, MultiKeyPipelineBase::xdel, key, + return connection.invoke().just(Jedis::xdel, PipelineBinaryCommands::xdel, key, StreamConverters.entryIdsToBytes(Arrays.asList(recordIds))); } @@ -125,7 +138,7 @@ public String xGroupCreate(byte[] key, String groupName, ReadOffset readOffset, Assert.hasText(groupName, "Group name must not be null or empty!"); Assert.notNull(readOffset, "ReadOffset must not be null!"); - return connection.invoke().just(BinaryJedis::xgroupCreate, MultiKeyPipelineBase::xgroupCreate, key, + return connection.invoke().just(Jedis::xgroupCreate, PipelineBinaryCommands::xgroupCreate, key, JedisConverters.toBytes(groupName), JedisConverters.toBytes(readOffset.getOffset()), mkStream); } @@ -135,7 +148,7 @@ public Boolean xGroupDelConsumer(byte[] key, Consumer consumer) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(consumer, "Consumer must not be null!"); - return connection.invoke().from(BinaryJedis::xgroupDelConsumer, MultiKeyPipelineBase::xgroupDelConsumer, key, + return connection.invoke().from(Jedis::xgroupDelConsumer, PipelineBinaryCommands::xgroupDelConsumer, key, JedisConverters.toBytes(consumer.getGroup()), JedisConverters.toBytes(consumer.getName())).get(r -> r > 0); } @@ -146,7 +159,7 @@ public Boolean xGroupDestroy(byte[] key, String groupName) { Assert.hasText(groupName, "Group name must not be null or empty!"); return connection.invoke() - .from(BinaryJedis::xgroupDestroy, MultiKeyPipelineBase::xgroupDestroy, key, JedisConverters.toBytes(groupName)) + .from(Jedis::xgroupDestroy, PipelineBinaryCommands::xgroupDestroy, key, JedisConverters.toBytes(groupName)) .get(r -> r > 0); } @@ -155,12 +168,8 @@ public StreamInfo.XInfoStream xInfo(byte[] key) { Assert.notNull(key, "Key must not be null!"); - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'XINFO' cannot be called in pipeline / transaction mode."); - } - - return connection.invoke().just(it -> { - redis.clients.jedis.StreamInfo streamInfo = it.xinfoStream(key); + return connection.invoke().from(Jedis::xinfoStream, ResponseCommands::xinfoStream, key).get(it -> { + redis.clients.jedis.resps.StreamInfo streamInfo = BuilderFactory.STREAM_INFO.build(it); return StreamInfo.XInfoStream.fromList(StreamConverters.mapToList(streamInfo.getStreamInfo())); }); } @@ -170,12 +179,8 @@ public StreamInfo.XInfoGroups xInfoGroups(byte[] key) { Assert.notNull(key, "Key must not be null!"); - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'XINFO GROUPS' cannot be called in pipeline / transaction mode."); - } - - return connection.invoke().just(it -> { - List streamGroupInfos = it.xinfoGroup(key); + return connection.invoke().from(Jedis::xinfoGroups, StreamPipelineBinaryCommands::xinfoGroups, key).get(it -> { + List streamGroupInfos = BuilderFactory.STREAM_GROUP_INFO_LIST.build(it); List sources = new ArrayList<>(); streamGroupInfos .forEach(streamGroupInfo -> sources.add(StreamConverters.mapToList(streamGroupInfo.getGroupInfo()))); @@ -189,18 +194,15 @@ public StreamInfo.XInfoConsumers xInfoConsumers(byte[] key, String groupName) { Assert.notNull(key, "Key must not be null!"); Assert.hasText(groupName, "Group name must not be null or empty!"); - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'XINFO CONSUMERS' cannot be called in pipeline / transaction mode."); - } - - return connection.invoke().just(it -> { - List streamConsumersInfos = it.xinfoConsumers(key, JedisConverters.toBytes(groupName)); - List sources = new ArrayList<>(); - streamConsumersInfos - .forEach( + return connection.invoke() + .from(Jedis::xinfoConsumers, ResponseCommands::xinfoConsumers, key, JedisConverters.toBytes(groupName)) + .get(it -> { + List streamConsumersInfos = BuilderFactory.STREAM_CONSUMERS_INFO_LIST.build(it); + List sources = new ArrayList<>(); + streamConsumersInfos.forEach( streamConsumersInfo -> sources.add(StreamConverters.mapToList(streamConsumersInfo.getConsumerInfo()))); - return StreamInfo.XInfoConsumers.fromList(groupName, sources); - }); + return StreamInfo.XInfoConsumers.fromList(groupName, sources); + }); } @Override @@ -208,12 +210,17 @@ public Long xLen(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::xlen, MultiKeyPipelineBase::xlen, key); + return connection.invoke().just(Jedis::xlen, PipelineBinaryCommands::xlen, key); } @Override public PendingMessagesSummary xPending(byte[] key, String groupName) { - throw new UnsupportedOperationException("Jedis does not support returning PendingMessagesSummary."); + + Assert.notNull(key, "Key must not be null!"); + + return connection.invoke() + .from(Jedis::xpending, PipelineBinaryCommands::xpending, key, JedisConverters.toBytes(groupName)) + .get(it -> StreamConverters.toPendingMessagesSummary(groupName, it)); } @Override @@ -223,16 +230,12 @@ public PendingMessages xPending(byte[] key, String groupName, XPendingOptions op Assert.notNull(groupName, "GroupName must not be null!"); Range range = (Range) options.getRange(); - byte[] group = JedisConverters.toBytes(groupName); + XPendingParams xPendingParams = StreamConverters.toXPendingParams(options); - return connection.invoke().from((it, t1, t2, t3, t4, t5, t6) -> { - Object r = it.xpending(t1, t2, t3, t4, t5, t6); - - return BuilderFactory.STREAM_PENDING_ENTRY_LIST.build(r); - }, MultiKeyPipelineBase::xpending, key, group, JedisConverters.toBytes(StreamConverters.getLowerValue(range)), - JedisConverters.toBytes(StreamConverters.getUpperValue(range)), options.getCount().intValue(), - JedisConverters.toBytes(options.getConsumerName())) - .get(r -> StreamConverters.toPendingMessages(groupName, range, r)); + return connection.invoke() + .from(Jedis::xpending, ResponseCommands::xpending, key, JedisConverters.toBytes(groupName), xPendingParams) + .get(r -> StreamConverters.toPendingMessages(groupName, range, + BuilderFactory.STREAM_PENDING_ENTRY_LIST.build(r))); } @Override @@ -245,11 +248,9 @@ public List xRange(byte[] key, Range range, Limit limit) { int count = limit.isUnlimited() ? Integer.MAX_VALUE : limit.getCount(); return connection.invoke() - .from( - it -> it.xrange(key, JedisConverters.toBytes(StreamConverters.getLowerValue(range)), - JedisConverters.toBytes(StreamConverters.getUpperValue(range)), count), - it -> it.xrange(key, JedisConverters.toBytes(StreamConverters.getLowerValue(range)), - JedisConverters.toBytes(StreamConverters.getUpperValue(range)), count)) + .from(Jedis::xrange, ResponseCommands::xrange, key, + JedisConverters.toBytes(StreamConverters.getLowerValue(range)), + JedisConverters.toBytes(StreamConverters.getUpperValue(range)), count) .get(r -> StreamConverters.convertToByteRecord(key, r)); } @@ -259,14 +260,10 @@ public List xRead(StreamReadOptions readOptions, StreamOffset it.xread(count, block, StreamConverters.toStreamOffsets(streams))) + return connection.invoke() + .from(Jedis::xread, ResponseCommands::xread, params, StreamConverters.toStreamOffsets(streams)) .getOrElse(StreamConverters::convertToByteRecords, Collections::emptyList); } @@ -278,18 +275,12 @@ public List xReadGroup(Consumer consumer, StreamReadOptions readOpti Assert.notNull(readOptions, "StreamReadOptions must not be null!"); Assert.notNull(streams, "StreamOffsets must not be null!"); - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'XREADGROUP' cannot be called in pipeline / transaction mode."); - } - - long block = readOptions.getBlock() == null ? -1L : readOptions.getBlock(); - int count = readOptions.getCount() == null ? -1 : readOptions.getCount().intValue(); + XReadGroupParams params = StreamConverters.toXReadGroupParams(readOptions); - return connection.invoke().from(it -> { - - return it.xreadGroup(JedisConverters.toBytes(consumer.getGroup()), JedisConverters.toBytes(consumer.getName()), - count, block, readOptions.isNoack(), StreamConverters.toStreamOffsets(streams)); - }).getOrElse(StreamConverters::convertToByteRecords, Collections::emptyList); + return connection.invoke() + .from(Jedis::xreadGroup, ResponseCommands::xreadGroup, JedisConverters.toBytes(consumer.getGroup()), + JedisConverters.toBytes(consumer.getName()), params, StreamConverters.toStreamOffsets(streams)) + .getOrElse(StreamConverters::convertToByteRecords, Collections::emptyList); } @Override @@ -301,7 +292,7 @@ public List xRevRange(byte[] key, Range range, Limit limit) int count = limit.isUnlimited() ? Integer.MAX_VALUE : limit.getCount(); return connection.invoke() - .from(BinaryJedis::xrevrange, MultiKeyPipelineBase::xrevrange, key, + .from(Jedis::xrevrange, ResponseCommands::xrevrange, key, JedisConverters.toBytes(StreamConverters.getUpperValue(range)), JedisConverters.toBytes(StreamConverters.getLowerValue(range)), count) .get(it -> StreamConverters.convertToByteRecord(key, it)); @@ -317,15 +308,7 @@ public Long xTrim(byte[] key, long count, boolean approximateTrimming) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::xtrim, MultiKeyPipelineBase::xtrim, key, count, approximateTrimming); - } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); + return connection.invoke().just(Jedis::xtrim, PipelineBinaryCommands::xtrim, key, count, approximateTrimming); } } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java index 19346f29fa..622645ff9f 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java @@ -15,9 +15,9 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.BitPosParams; -import redis.clients.jedis.MultiKeyPipelineBase; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.PipelineBinaryCommands; +import redis.clients.jedis.params.BitPosParams; import redis.clients.jedis.params.SetParams; import java.util.List; @@ -50,7 +50,7 @@ public byte[] get(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::get, MultiKeyPipelineBase::get, key); + return connection.invoke().just(Jedis::get, PipelineBinaryCommands::get, key); } @Nullable @@ -59,7 +59,7 @@ public byte[] getDel(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::getDel, MultiKeyPipelineBase::getDel, key); + return connection.invoke().just(Jedis::getDel, PipelineBinaryCommands::getDel, key); } @Nullable @@ -69,7 +69,7 @@ public byte[] getEx(byte[] key, Expiration expiration) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(expiration, "Expiration must not be null!"); - return connection.invoke().just(BinaryJedis::getEx, MultiKeyPipelineBase::getEx, key, + return connection.invoke().just(Jedis::getEx, PipelineBinaryCommands::getEx, key, JedisConverters.toGetExParams(expiration)); } @@ -79,7 +79,7 @@ public byte[] getSet(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::getSet, MultiKeyPipelineBase::getSet, key, value); + return connection.invoke().just(Jedis::getSet, PipelineBinaryCommands::getSet, key, value); } @Override @@ -88,7 +88,7 @@ public List mGet(byte[]... keys) { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - return connection.invoke().just(BinaryJedis::mget, MultiKeyPipelineBase::mget, keys); + return connection.invoke().just(Jedis::mget, PipelineBinaryCommands::mget, keys); } @Override @@ -97,7 +97,7 @@ public Boolean set(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().from(BinaryJedis::set, MultiKeyPipelineBase::set, key, value) + return connection.invoke().from(Jedis::set, PipelineBinaryCommands::set, key, value) .get(Converters.stringToBooleanConverter()); } @@ -112,7 +112,7 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op SetParams params = JedisConverters.toSetCommandExPxArgument(expiration, JedisConverters.toSetCommandNxXxArgument(option)); - return connection.invoke().from(BinaryJedis::set, MultiKeyPipelineBase::set, key, value, params) + return connection.invoke().from(Jedis::set, PipelineBinaryCommands::set, key, value, params) .getOrElse(Converters.stringToBooleanConverter(), () -> false); } @@ -122,7 +122,7 @@ public Boolean setNX(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().from(BinaryJedis::setnx, MultiKeyPipelineBase::setnx, key, value) + return connection.invoke().from(Jedis::setnx, PipelineBinaryCommands::setnx, key, value) .get(Converters.longToBoolean()); } @@ -136,7 +136,7 @@ public Boolean setEx(byte[] key, long seconds, byte[] value) { throw new IllegalArgumentException("Time must be less than Integer.MAX_VALUE for setEx in Jedis."); } - return connection.invoke().from(BinaryJedis::setex, MultiKeyPipelineBase::setex, key, (int) seconds, value) + return connection.invoke().from(Jedis::setex, PipelineBinaryCommands::setex, key, seconds, value) .getOrElse(Converters.stringToBooleanConverter(), () -> false); } @@ -146,7 +146,7 @@ public Boolean pSetEx(byte[] key, long milliseconds, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().from(BinaryJedis::psetex, MultiKeyPipelineBase::psetex, key, milliseconds, value) + return connection.invoke().from(Jedis::psetex, PipelineBinaryCommands::psetex, key, milliseconds, value) .getOrElse(Converters.stringToBooleanConverter(), () -> false); } @@ -155,7 +155,7 @@ public Boolean mSet(Map tuples) { Assert.notNull(tuples, "Tuples must not be null!"); - return connection.invoke().from(BinaryJedis::mset, MultiKeyPipelineBase::mset, JedisConverters.toByteArrays(tuples)) + return connection.invoke().from(Jedis::mset, PipelineBinaryCommands::mset, JedisConverters.toByteArrays(tuples)) .get(Converters.stringToBooleanConverter()); } @@ -164,8 +164,7 @@ public Boolean mSetNX(Map tuples) { Assert.notNull(tuples, "Tuples must not be null!"); - return connection.invoke() - .from(BinaryJedis::msetnx, MultiKeyPipelineBase::msetnx, JedisConverters.toByteArrays(tuples)) + return connection.invoke().from(Jedis::msetnx, PipelineBinaryCommands::msetnx, JedisConverters.toByteArrays(tuples)) .get(Converters.longToBoolean()); } @@ -174,7 +173,7 @@ public Long incr(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::incr, MultiKeyPipelineBase::incr, key); + return connection.invoke().just(Jedis::incr, PipelineBinaryCommands::incr, key); } @Override @@ -182,7 +181,7 @@ public Long incrBy(byte[] key, long value) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::incrBy, MultiKeyPipelineBase::incrBy, key, value); + return connection.invoke().just(Jedis::incrBy, PipelineBinaryCommands::incrBy, key, value); } @Override @@ -190,7 +189,7 @@ public Double incrBy(byte[] key, double value) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::incrByFloat, MultiKeyPipelineBase::incrByFloat, key, value); + return connection.invoke().just(Jedis::incrByFloat, PipelineBinaryCommands::incrByFloat, key, value); } @Override @@ -198,7 +197,7 @@ public Long decr(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::decr, MultiKeyPipelineBase::decr, key); + return connection.invoke().just(Jedis::decr, PipelineBinaryCommands::decr, key); } @Override @@ -206,7 +205,7 @@ public Long decrBy(byte[] key, long value) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::decrBy, MultiKeyPipelineBase::decrBy, key, value); + return connection.invoke().just(Jedis::decrBy, PipelineBinaryCommands::decrBy, key, value); } @Override @@ -215,7 +214,7 @@ public Long append(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::append, MultiKeyPipelineBase::append, key, value); + return connection.invoke().just(Jedis::append, PipelineBinaryCommands::append, key, value); } @Override @@ -223,7 +222,7 @@ public byte[] getRange(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::getrange, MultiKeyPipelineBase::getrange, key, start, end); + return connection.invoke().just(Jedis::getrange, PipelineBinaryCommands::getrange, key, start, end); } @Override @@ -232,7 +231,7 @@ public void setRange(byte[] key, byte[] value, long offset) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - connection.invokeStatus().just(BinaryJedis::setrange, MultiKeyPipelineBase::setrange, key, offset, value); + connection.invokeStatus().just(Jedis::setrange, PipelineBinaryCommands::setrange, key, offset, value); } @Override @@ -240,7 +239,7 @@ public Boolean getBit(byte[] key, long offset) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::getbit, MultiKeyPipelineBase::getbit, key, offset); + return connection.invoke().just(Jedis::getbit, PipelineBinaryCommands::getbit, key, offset); } @Override @@ -248,8 +247,7 @@ public Boolean setBit(byte[] key, long offset, boolean value) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::setbit, MultiKeyPipelineBase::setbit, key, offset, - JedisConverters.toBit(value)); + return connection.invoke().just(Jedis::setbit, PipelineBinaryCommands::setbit, key, offset, value); } @Override @@ -257,7 +255,7 @@ public Long bitCount(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::bitcount, MultiKeyPipelineBase::bitcount, key); + return connection.invoke().just(Jedis::bitcount, PipelineBinaryCommands::bitcount, key); } @Override @@ -265,7 +263,7 @@ public Long bitCount(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::bitcount, MultiKeyPipelineBase::bitcount, key, start, end); + return connection.invoke().just(Jedis::bitcount, PipelineBinaryCommands::bitcount, key, start, end); } @Override @@ -274,7 +272,7 @@ public List bitField(byte[] key, BitFieldSubCommands subCommands) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(subCommands, "Command must not be null!"); - return connection.invoke().just(BinaryJedis::bitfield, MultiKeyPipelineBase::bitfield, key, + return connection.invoke().just(Jedis::bitfield, PipelineBinaryCommands::bitfield, key, JedisConverters.toBitfieldCommandArguments(subCommands)); } @@ -285,10 +283,10 @@ public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { Assert.notNull(destination, "Destination key must not be null!"); if (op == BitOperation.NOT && keys.length > 1) { - throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); + throw new IllegalArgumentException("Bitop NOT should only be performed against one key"); } - return connection.invoke().just(BinaryJedis::bitop, MultiKeyPipelineBase::bitop, JedisConverters.toBitOp(op), + return connection.invoke().just(Jedis::bitop, PipelineBinaryCommands::bitop, JedisConverters.toBitOp(op), destination, keys); } @@ -305,10 +303,10 @@ public Long bitPos(byte[] key, boolean bit, Range range) { ? new BitPosParams(range.getLowerBound().getValue().get(), range.getUpperBound().getValue().get()) : new BitPosParams(range.getLowerBound().getValue().get()); - return connection.invoke().just(BinaryJedis::bitpos, MultiKeyPipelineBase::bitpos, key, bit, params); + return connection.invoke().just(Jedis::bitpos, PipelineBinaryCommands::bitpos, key, bit, params); } - return connection.invoke().just(BinaryJedis::bitpos, MultiKeyPipelineBase::bitpos, key, bit); + return connection.invoke().just(Jedis::bitpos, PipelineBinaryCommands::bitpos, key, bit); } @Override @@ -316,7 +314,7 @@ public Long strLen(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::strlen, MultiKeyPipelineBase::strlen, key); + return connection.invoke().just(Jedis::strlen, PipelineBinaryCommands::strlen, key); } } 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 7a8d1960fb..347089639e 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 @@ -15,19 +15,18 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; import redis.clients.jedis.Jedis; -import redis.clients.jedis.MultiKeyPipelineBase; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; -import redis.clients.jedis.ZParams; +import redis.clients.jedis.commands.PipelineBinaryCommands; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.params.ZParams; +import redis.clients.jedis.resps.ScanResult; -import java.nio.charset.StandardCharsets; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.zset.DefaultTuple; import org.springframework.data.redis.connection.zset.Tuple; @@ -61,7 +60,7 @@ public Boolean zAdd(byte[] key, double score, byte[] value, ZAddArgs args) { Assert.notNull(value, "Value must not be null!"); return connection.invoke() - .from(BinaryJedis::zadd, MultiKeyPipelineBase::zadd, key, score, value, JedisConverters.toZAddParams(args)) + .from(Jedis::zadd, PipelineBinaryCommands::zadd, key, score, value, JedisConverters.toZAddParams(args)) .get(JedisConverters::toBoolean); } @@ -71,8 +70,8 @@ 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(BinaryJedis::zadd, MultiKeyPipelineBase::zadd, key, - JedisConverters.toTupleMap(tuples), JedisConverters.toZAddParams(args)); + return connection.invoke().just(Jedis::zadd, PipelineBinaryCommands::zadd, key, JedisConverters.toTupleMap(tuples), + JedisConverters.toZAddParams(args)); } @Override @@ -82,7 +81,7 @@ public Long zRem(byte[] key, byte[]... values) { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - return connection.invoke().just(BinaryJedis::zrem, MultiKeyPipelineBase::zrem, key, values); + return connection.invoke().just(Jedis::zrem, PipelineBinaryCommands::zrem, key, values); } @Override @@ -91,7 +90,7 @@ public Double zIncrBy(byte[] key, double increment, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::zincrby, MultiKeyPipelineBase::zincrby, key, increment, value); + return connection.invoke().just(Jedis::zincrby, PipelineBinaryCommands::zincrby, key, increment, value); } @Override @@ -99,7 +98,7 @@ public byte[] zRandMember(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::zrandmember, MultiKeyPipelineBase::zrandmember, key); + return connection.invoke().just(Jedis::zrandmember, PipelineBinaryCommands::zrandmember, key); } @Override @@ -107,8 +106,7 @@ public List zRandMember(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().fromMany(BinaryJedis::zrandmember, MultiKeyPipelineBase::zrandmember, key, count) - .toList(); + return connection.invoke().fromMany(Jedis::zrandmember, PipelineBinaryCommands::zrandmember, key, count).toList(); } @Override @@ -117,7 +115,7 @@ public Tuple zRandMemberWithScore(byte[] key) { Assert.notNull(key, "Key must not be null!"); return connection.invoke() - .from(BinaryJedis::zrandmemberWithScores, MultiKeyPipelineBase::zrandmemberWithScores, key, 1L).get(it -> { + .from(Jedis::zrandmemberWithScores, PipelineBinaryCommands::zrandmemberWithScores, key, 1L).get(it -> { if (it.isEmpty()) { return null; @@ -133,7 +131,7 @@ public List zRandMemberWithScore(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); return connection.invoke() - .fromMany(BinaryJedis::zrandmemberWithScores, MultiKeyPipelineBase::zrandmemberWithScores, key, count) + .fromMany(Jedis::zrandmemberWithScores, PipelineBinaryCommands::zrandmemberWithScores, key, count) .toList(JedisConverters::toTuple); } @@ -143,7 +141,7 @@ public Long zRank(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::zrank, MultiKeyPipelineBase::zrank, key, value); + return connection.invoke().just(Jedis::zrank, PipelineBinaryCommands::zrank, key, value); } @Override @@ -151,7 +149,7 @@ public Long zRevRank(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::zrevrank, MultiKeyPipelineBase::zrevrank, key, value); + return connection.invoke().just(Jedis::zrevrank, PipelineBinaryCommands::zrevrank, key, value); } @Override @@ -159,7 +157,7 @@ public Set zRange(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::zrange, MultiKeyPipelineBase::zrange, key, start, end); + return connection.invoke().fromMany(Jedis::zrange, PipelineBinaryCommands::zrange, key, start, end).toSet(); } @Override @@ -168,7 +166,7 @@ public Set zRangeWithScores(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); return connection.invoke() - .fromMany(BinaryJedis::zrangeWithScores, MultiKeyPipelineBase::zrangeWithScores, key, start, end) + .fromMany(Jedis::zrangeWithScores, PipelineBinaryCommands::zrangeWithScores, key, start, end) .toSet(JedisConverters::toTuple); } @@ -184,13 +182,13 @@ public Set zRangeByScoreWithScores(byte[] key, Range range, byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); if (!limit.isUnlimited()) { - return connection.invoke().fromMany(BinaryJedis::zrangeByScoreWithScores, - MultiKeyPipelineBase::zrangeByScoreWithScores, key, min, max, limit.getOffset(), limit.getCount()) + return connection.invoke().fromMany(Jedis::zrangeByScoreWithScores, + PipelineBinaryCommands::zrangeByScoreWithScores, key, min, max, limit.getOffset(), limit.getCount()) .toSet(JedisConverters::toTuple); } return connection.invoke() - .fromMany(BinaryJedis::zrangeByScoreWithScores, MultiKeyPipelineBase::zrangeByScoreWithScores, key, min, max) + .fromMany(Jedis::zrangeByScoreWithScores, PipelineBinaryCommands::zrangeByScoreWithScores, key, min, max) .toSet(JedisConverters::toTuple); } @@ -199,7 +197,7 @@ public Set zRevRange(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::zrevrange, MultiKeyPipelineBase::zrevrange, key, start, end); + return connection.invoke().fromMany(Jedis::zrevrange, PipelineBinaryCommands::zrevrange, key, start, end).toSet(); } @Override @@ -208,7 +206,7 @@ public Set zRevRangeWithScores(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); return connection.invoke() - .fromMany(BinaryJedis::zrevrangeWithScores, MultiKeyPipelineBase::zrevrangeWithScores, key, start, end) + .fromMany(Jedis::zrevrangeWithScores, PipelineBinaryCommands::zrevrangeWithScores, key, start, end) .toSet(JedisConverters::toTuple); } @@ -223,12 +221,12 @@ public Set zRevRangeByScore(byte[] key, Range range, org.springframework byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); if (!limit.isUnlimited()) { - return connection.invoke().just(BinaryJedis::zrevrangeByScore, MultiKeyPipelineBase::zrevrangeByScore, key, max, - min, limit.getOffset(), limit.getCount()); + return connection.invoke().fromMany(Jedis::zrevrangeByScore, PipelineBinaryCommands::zrevrangeByScore, key, max, + min, limit.getOffset(), limit.getCount()).toSet(); } - return connection.invoke().just(BinaryJedis::zrevrangeByScore, MultiKeyPipelineBase::zrevrangeByScore, key, max, - min); + return connection.invoke() + .fromMany(Jedis::zrevrangeByScore, PipelineBinaryCommands::zrevrangeByScore, key, max, min).toSet(); } @Override @@ -243,13 +241,14 @@ public Set zRevRangeByScoreWithScores(byte[] key, Range range, byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); if (!limit.isUnlimited()) { - return connection.invoke().fromMany(BinaryJedis::zrevrangeByScoreWithScores, - MultiKeyPipelineBase::zrevrangeByScoreWithScores, key, max, min, limit.getOffset(), limit.getCount()) + return connection.invoke().fromMany(Jedis::zrevrangeByScoreWithScores, + PipelineBinaryCommands::zrevrangeByScoreWithScores, key, max, min, limit.getOffset(), limit.getCount()) .toSet(JedisConverters::toTuple); } - return connection.invoke().fromMany(BinaryJedis::zrevrangeByScoreWithScores, - MultiKeyPipelineBase::zrevrangeByScoreWithScores, key, max, min).toSet(JedisConverters::toTuple); + return connection.invoke() + .fromMany(Jedis::zrevrangeByScoreWithScores, PipelineBinaryCommands::zrevrangeByScoreWithScores, key, max, min) + .toSet(JedisConverters::toTuple); } @Override @@ -257,7 +256,7 @@ public Long zCount(byte[] key, double min, double max) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::zcount, MultiKeyPipelineBase::zcount, key, min, max); + return connection.invoke().just(Jedis::zcount, PipelineBinaryCommands::zcount, key, min, max); } @Override @@ -269,7 +268,7 @@ public Long zCount(byte[] key, Range range) { byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - return connection.invoke().just(BinaryJedis::zcount, MultiKeyPipelineBase::zcount, key, min, max); + return connection.invoke().just(Jedis::zcount, PipelineBinaryCommands::zcount, key, min, max); } @Override @@ -281,7 +280,7 @@ public Long zLexCount(byte[] key, Range range) { byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); - return connection.invoke().just(BinaryJedis::zlexcount, MultiKeyPipelineBase::zlexcount, key, min, max); + return connection.invoke().just(Jedis::zlexcount, PipelineBinaryCommands::zlexcount, key, min, max); } @Nullable @@ -290,8 +289,7 @@ public Tuple zPopMin(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::zpopmin, MultiKeyPipelineBase::zpopmin, key) - .get(JedisConverters::toTuple); + return connection.invoke().from(Jedis::zpopmin, PipelineBinaryCommands::zpopmin, key).get(JedisConverters::toTuple); } @Nullable @@ -300,8 +298,7 @@ public Set zPopMin(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke() - .fromMany(BinaryJedis::zpopmin, MultiKeyPipelineBase::zpopmin, key, Math.toIntExact(count)) + return connection.invoke().fromMany(Jedis::zpopmin, PipelineBinaryCommands::zpopmin, key, Math.toIntExact(count)) .toSet(JedisConverters::toTuple); } @@ -313,7 +310,7 @@ public Tuple bZPopMin(byte[] key, long timeout, TimeUnit unit) { Assert.notNull(unit, "TimeUnit must not be null!"); return connection.invoke() - .from(BinaryJedis::bzpopmin, MultiKeyPipelineBase::bzpopmin, JedisConverters.toSeconds(timeout, unit), key) + .from(Jedis::bzpopmin, PipelineBinaryCommands::bzpopmin, JedisConverters.toSeconds(timeout, unit), key) .get(JedisZSetCommands::toTuple); } @@ -323,8 +320,7 @@ public Tuple zPopMax(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().from(BinaryJedis::zpopmax, MultiKeyPipelineBase::zpopmax, key) - .get(JedisConverters::toTuple); + return connection.invoke().from(Jedis::zpopmax, PipelineBinaryCommands::zpopmax, key).get(JedisConverters::toTuple); } @Nullable @@ -333,8 +329,7 @@ public Set zPopMax(byte[] key, long count) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke() - .fromMany(BinaryJedis::zpopmax, MultiKeyPipelineBase::zpopmax, key, Math.toIntExact(count)) + return connection.invoke().fromMany(Jedis::zpopmax, PipelineBinaryCommands::zpopmax, key, Math.toIntExact(count)) .toSet(JedisConverters::toTuple); } @@ -346,7 +341,7 @@ public Tuple bZPopMax(byte[] key, long timeout, TimeUnit unit) { Assert.notNull(unit, "TimeUnit must not be null!"); return connection.invoke() - .from(BinaryJedis::bzpopmax, MultiKeyPipelineBase::bzpopmax, JedisConverters.toSeconds(timeout, unit), key) + .from(Jedis::bzpopmax, PipelineBinaryCommands::bzpopmax, JedisConverters.toSeconds(timeout, unit), key) .get(JedisZSetCommands::toTuple); } @@ -355,7 +350,7 @@ public Long zCard(byte[] key) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::zcard, MultiKeyPipelineBase::zcard, key); + return connection.invoke().just(Jedis::zcard, PipelineBinaryCommands::zcard, key); } @Override @@ -364,7 +359,7 @@ public Double zScore(byte[] key, byte[] value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::zscore, MultiKeyPipelineBase::zscore, key, value); + return connection.invoke().just(Jedis::zscore, PipelineBinaryCommands::zscore, key, value); } @Override @@ -373,7 +368,7 @@ public List zMScore(byte[] key, byte[][] values) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(values, "Value must not be null!"); - return connection.invoke().just(BinaryJedis::zmscore, MultiKeyPipelineBase::zmscore, key, values); + return connection.invoke().just(Jedis::zmscore, PipelineBinaryCommands::zmscore, key, values); } @Override @@ -381,8 +376,7 @@ public Long zRemRange(byte[] key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return connection.invoke().just(BinaryJedis::zremrangeByRank, MultiKeyPipelineBase::zremrangeByRank, key, start, - end); + return connection.invoke().just(Jedis::zremrangeByRank, PipelineBinaryCommands::zremrangeByRank, key, start, end); } @Override @@ -394,7 +388,7 @@ public Long zRemRangeByLex(byte[] key, Range range) { byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); - return connection.invoke().just(BinaryJedis::zremrangeByLex, MultiKeyPipelineBase::zremrangeByLex, key, min, max); + return connection.invoke().just(Jedis::zremrangeByLex, PipelineBinaryCommands::zremrangeByLex, key, min, max); } @Override @@ -406,8 +400,7 @@ public Long zRemRangeByScore(byte[] key, Range range) { byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - return connection.invoke().just(BinaryJedis::zremrangeByScore, MultiKeyPipelineBase::zremrangeByScore, key, min, - max); + return connection.invoke().just(Jedis::zremrangeByScore, PipelineBinaryCommands::zremrangeByScore, key, min, max); } @Override @@ -415,7 +408,7 @@ public Set zDiff(byte[]... sets) { Assert.notNull(sets, "Sets must not be null!"); - return connection.invoke().just(BinaryJedis::zdiff, MultiKeyPipelineBase::zdiff, sets); + return connection.invoke().just(Jedis::zdiff, PipelineBinaryCommands::zdiff, sets); } @Override @@ -423,7 +416,7 @@ public Set zDiffWithScores(byte[]... sets) { Assert.notNull(sets, "Sets must not be null!"); - return connection.invoke().fromMany(BinaryJedis::zdiffWithScores, MultiKeyPipelineBase::zdiffWithScores, sets) + return connection.invoke().fromMany(Jedis::zdiffWithScores, PipelineBinaryCommands::zdiffWithScores, sets) .toSet(JedisConverters::toTuple); } @@ -433,7 +426,7 @@ public Long zDiffStore(byte[] destKey, byte[]... sets) { Assert.notNull(destKey, "Destination key must not be null!"); Assert.notNull(sets, "Source sets must not be null!"); - return connection.invoke().just(BinaryJedis::zdiffStore, MultiKeyPipelineBase::zdiffStore, destKey, sets); + return connection.invoke().just(Jedis::zdiffStore, PipelineBinaryCommands::zdiffStore, destKey, sets); } @Override @@ -441,7 +434,7 @@ public Set zInter(byte[]... sets) { Assert.notNull(sets, "Sets must not be null!"); - return connection.invoke().just(BinaryJedis::zinter, MultiKeyPipelineBase::zinter, new ZParams(), sets); + return connection.invoke().just(Jedis::zinter, PipelineBinaryCommands::zinter, new ZParams(), sets); } @Override @@ -450,7 +443,7 @@ public Set zInterWithScores(byte[]... sets) { Assert.notNull(sets, "Sets must not be null!"); return connection.invoke() - .fromMany(BinaryJedis::zinterWithScores, MultiKeyPipelineBase::zinterWithScores, new ZParams(), sets) + .fromMany(Jedis::zinterWithScores, PipelineBinaryCommands::zinterWithScores, new ZParams(), sets) .toSet(JedisConverters::toTuple); } @@ -462,7 +455,7 @@ public Set zInterWithScores(Aggregate aggregate, Weights weights, byte[]. Assert.isTrue(weights.size() == sets.length, () -> String .format("The number of weights (%d) must match the number of source sets (%d)!", weights.size(), sets.length)); - return connection.invoke().fromMany(BinaryJedis::zinterWithScores, MultiKeyPipelineBase::zinterWithScores, + return connection.invoke().fromMany(Jedis::zinterWithScores, PipelineBinaryCommands::zinterWithScores, toZParams(aggregate, weights), sets).toSet(JedisConverters::toTuple); } @@ -477,8 +470,7 @@ public Long zInterStore(byte[] destKey, Aggregate aggregate, Weights weights, by ZParams zparams = toZParams(aggregate, weights); - return connection.invoke().just(BinaryJedis::zinterstore, MultiKeyPipelineBase::zinterstore, destKey, zparams, - sets); + return connection.invoke().just(Jedis::zinterstore, PipelineBinaryCommands::zinterstore, destKey, zparams, sets); } @Override @@ -488,7 +480,7 @@ public Long zInterStore(byte[] destKey, byte[]... sets) { Assert.notNull(sets, "Source sets must not be null!"); Assert.noNullElements(sets, "Source sets must not contain null elements!"); - return connection.invoke().just(BinaryJedis::zinterstore, MultiKeyPipelineBase::zinterstore, destKey, sets); + return connection.invoke().just(Jedis::zinterstore, PipelineBinaryCommands::zinterstore, destKey, sets); } @Override @@ -496,7 +488,7 @@ public Set zUnion(byte[]... sets) { Assert.notNull(sets, "Sets must not be null!"); - return connection.invoke().just(BinaryJedis::zunion, MultiKeyPipelineBase::zunion, new ZParams(), sets); + return connection.invoke().just(Jedis::zunion, PipelineBinaryCommands::zunion, new ZParams(), sets); } @Override @@ -505,7 +497,7 @@ public Set zUnionWithScores(byte[]... sets) { Assert.notNull(sets, "Sets must not be null!"); return connection.invoke() - .fromMany(BinaryJedis::zunionWithScores, MultiKeyPipelineBase::zunionWithScores, new ZParams(), sets) + .fromMany(Jedis::zunionWithScores, PipelineBinaryCommands::zunionWithScores, new ZParams(), sets) .toSet(JedisConverters::toTuple); } @@ -517,7 +509,7 @@ public Set zUnionWithScores(Aggregate aggregate, Weights weights, byte[]. Assert.isTrue(weights.size() == sets.length, () -> String .format("The number of weights (%d) must match the number of source sets (%d)!", weights.size(), sets.length)); - return connection.invoke().fromMany(BinaryJedis::zunionWithScores, MultiKeyPipelineBase::zunionWithScores, + return connection.invoke().fromMany(Jedis::zunionWithScores, PipelineBinaryCommands::zunionWithScores, toZParams(aggregate, weights), sets).toSet(JedisConverters::toTuple); } @@ -533,8 +525,7 @@ public Long zUnionStore(byte[] destKey, Aggregate aggregate, Weights weights, by ZParams zparams = toZParams(aggregate, weights); - return connection.invoke().just(BinaryJedis::zunionstore, MultiKeyPipelineBase::zunionstore, destKey, zparams, - sets); + return connection.invoke().just(Jedis::zunionstore, PipelineBinaryCommands::zunionstore, destKey, zparams, sets); } @Override @@ -544,7 +535,7 @@ public Long zUnionStore(byte[] destKey, byte[]... sets) { Assert.notNull(sets, "Source sets must not be null!"); Assert.noNullElements(sets, "Source sets must not contain null elements!"); - return connection.invoke().just(BinaryJedis::zunionstore, MultiKeyPipelineBase::zunionstore, destKey, sets); + return connection.invoke().just(Jedis::zunionstore, PipelineBinaryCommands::zunionstore, destKey, sets); } @Override @@ -569,12 +560,12 @@ public Cursor zScan(byte[] key, Long cursorId, ScanOptions options) { protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'ZSCAN' cannot be called in pipeline / transaction mode."); } ScanParams params = JedisConverters.toScanParams(options); - ScanResult result = connection.getJedis().zscan(key, + ScanResult result = connection.getJedis().zscan(key, JedisConverters.toBytes(cursorId), params); return new ScanIteration<>(Long.valueOf(result.getCursor()), JedisConverters.tuplesToTuples().convert(result.getResult())); @@ -593,9 +584,8 @@ public Set zRangeByScore(byte[] key, String min, String max) { Assert.notNull(key, "Key must not be null!"); - String keyStr = new String(key, StandardCharsets.UTF_8); - return connection.invoke().fromMany(Jedis::zrangeByScore, MultiKeyPipelineBase::zrangeByScore, keyStr, min, max) - .toSet(JedisConverters::toBytes); + return connection.invoke().fromMany(Jedis::zrangeByScore, PipelineBinaryCommands::zrangeByScore, key, + JedisConverters.toBytes(min), JedisConverters.toBytes(max)).toSet(); } @Override @@ -608,10 +598,9 @@ public Set zRangeByScore(byte[] key, String min, String max, long offset throw new IllegalArgumentException( "Offset and count must be less than Integer.MAX_VALUE for zRangeByScore in Jedis."); } - String keyStr = new String(key, StandardCharsets.UTF_8); - return connection.invoke().fromMany(Jedis::zrangeByScore, MultiKeyPipelineBase::zrangeByScore, keyStr, min, max, - (int) offset, (int) count).toSet(JedisConverters::toBytes); + return connection.invoke().fromMany(Jedis::zrangeByScore, PipelineBinaryCommands::zrangeByScore, key, + JedisConverters.toBytes(min), JedisConverters.toBytes(max), (int) offset, (int) count).toSet(); } @Override @@ -625,11 +614,12 @@ public Set zRangeByScore(byte[] key, Range range, org.springframework.da byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); if (!limit.isUnlimited()) { - return connection.invoke().just(BinaryJedis::zrangeByScore, MultiKeyPipelineBase::zrangeByScore, key, min, max, - limit.getOffset(), limit.getCount()); + return connection.invoke().fromMany(Jedis::zrangeByScore, PipelineBinaryCommands::zrangeByScore, key, min, max, + limit.getOffset(), limit.getCount()).toSet(); } - return connection.invoke().just(BinaryJedis::zrangeByScore, MultiKeyPipelineBase::zrangeByScore, key, min, max); + return connection.invoke().fromMany(Jedis::zrangeByScore, PipelineBinaryCommands::zrangeByScore, key, min, max) + .toSet(); } @Override @@ -643,11 +633,11 @@ public Set zRangeByLex(byte[] key, Range range, org.springframework.data byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); if (!limit.isUnlimited()) { - return connection.invoke().just(BinaryJedis::zrangeByLex, MultiKeyPipelineBase::zrangeByLex, key, min, max, - limit.getOffset(), limit.getCount()); + return connection.invoke().fromMany(Jedis::zrangeByLex, PipelineBinaryCommands::zrangeByLex, key, min, max, + limit.getOffset(), limit.getCount()).toSet(); } - return connection.invoke().just(BinaryJedis::zrangeByLex, MultiKeyPipelineBase::zrangeByLex, key, min, max); + return connection.invoke().fromMany(Jedis::zrangeByLex, PipelineBinaryCommands::zrangeByLex, key, min, max).toSet(); } @Override @@ -661,11 +651,11 @@ public Set zRevRangeByLex(byte[] key, Range range, org.springframework.d byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); if (!limit.isUnlimited()) { - return connection.invoke().from(BinaryJedis::zrevrangeByLex, MultiKeyPipelineBase::zrevrangeByLex, key, max, min, + return connection.invoke().from(Jedis::zrevrangeByLex, PipelineBinaryCommands::zrevrangeByLex, key, max, min, limit.getOffset(), limit.getCount()).get(LinkedHashSet::new); } - return connection.invoke().from(BinaryJedis::zrevrangeByLex, MultiKeyPipelineBase::zrevrangeByLex, key, max, min) + return connection.invoke().from(Jedis::zrevrangeByLex, PipelineBinaryCommands::zrevrangeByLex, key, max, min) .get(LinkedHashSet::new); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/StreamConverters.java b/src/main/java/org/springframework/data/redis/connection/jedis/StreamConverters.java index 0214c3f2f8..9e6c5e20c5 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/StreamConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/StreamConverters.java @@ -15,15 +15,21 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.StreamEntry; +import redis.clients.jedis.BuilderFactory; import redis.clients.jedis.StreamEntryID; -import redis.clients.jedis.StreamPendingEntry; import redis.clients.jedis.params.XAddParams; +import redis.clients.jedis.params.XClaimParams; +import redis.clients.jedis.params.XPendingParams; +import redis.clients.jedis.params.XReadGroupParams; +import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.resps.StreamEntry; +import redis.clients.jedis.resps.StreamPendingEntry; import redis.clients.jedis.util.SafeEncoder; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -34,11 +40,12 @@ import org.springframework.data.redis.connection.RedisStreamCommands; import org.springframework.data.redis.connection.stream.ByteRecord; import org.springframework.data.redis.connection.stream.Consumer; -import org.springframework.data.redis.connection.stream.MapRecord; import org.springframework.data.redis.connection.stream.PendingMessage; import org.springframework.data.redis.connection.stream.PendingMessages; +import org.springframework.data.redis.connection.stream.PendingMessagesSummary; import org.springframework.data.redis.connection.stream.RecordId; import org.springframework.data.redis.connection.stream.StreamOffset; +import org.springframework.data.redis.connection.stream.StreamReadOptions; import org.springframework.data.redis.connection.stream.StreamRecords; /** @@ -103,9 +110,10 @@ static List mapToList(Map map) { return sources; } - static Map toStreamOffsets(StreamOffset[] streams) { + static Map.Entry[] toStreamOffsets(StreamOffset[] streams) { return Arrays.stream(streams) - .collect(Collectors.toMap(StreamOffset::getKey, v -> JedisConverters.toBytes(v.getOffset().getOffset()))); + .collect(Collectors.toMap(StreamOffset::getKey, v -> JedisConverters.toBytes(v.getOffset().getOffset()))) + .entrySet().toArray(new Map.Entry[0]); } static List convertToByteRecord(byte[] key, Object source) { @@ -150,6 +158,32 @@ static List convertToByteRecords(List sources) { return result; } + static PendingMessagesSummary toPendingMessagesSummary(String groupName, Object source) { + + List objectList = (List) source; + long total = BuilderFactory.LONG.build(objectList.get(0)); + Range.Bound lower = objectList.get(1) != null + ? Range.Bound.inclusive(SafeEncoder.encode((byte[]) objectList.get(1))) + : Range.Bound.unbounded(); + Range.Bound upper = objectList.get(2) != null + ? Range.Bound.inclusive(SafeEncoder.encode((byte[]) objectList.get(2))) + : Range.Bound.unbounded(); + List> consumerObjList = (List>) objectList.get(3); + Map map; + + if (consumerObjList != null) { + map = new HashMap<>(consumerObjList.size()); + for (List consumerObj : consumerObjList) { + map.put(SafeEncoder.encode((byte[]) consumerObj.get(0)), + Long.parseLong(SafeEncoder.encode((byte[]) consumerObj.get(1)))); + } + } else { + map = Collections.emptyMap(); + } + + return new PendingMessagesSummary(groupName, total, Range.of(lower, upper), map); + } + /** * Convert the raw Jedis xpending result to {@link PendingMessages}. * @@ -170,10 +204,10 @@ static org.springframework.data.redis.connection.stream.PendingMessages toPendin return new PendingMessages(groupName, messages).withinRange(range); } - static XAddParams toXAddParams(MapRecord record, RedisStreamCommands.XAddOptions options) { + public static XAddParams toXAddParams(RecordId recordId, RedisStreamCommands.XAddOptions options) { - XAddParams params = XAddParams.xAddParams(); - params.id(record.getId().getValue()); + XAddParams params = new XAddParams(); + params.id(toStreamEntryId(recordId.getValue())); if (options.hasMaxlen()) { params.maxLen(options.getMaxlen()); @@ -193,4 +227,89 @@ static XAddParams toXAddParams(MapRecord record, RedisSt return params; } + + private static StreamEntryID toStreamEntryId(String value) { + + if ("*".equals(value)) { + return StreamEntryID.NEW_ENTRY; + } + + if ("$".equals(value)) { + return StreamEntryID.LAST_ENTRY; + } + + if (">".equals(value)) { + return StreamEntryID.UNRECEIVED_ENTRY; + } + + return new StreamEntryID(value); + } + + public static XClaimParams toXClaimParams(RedisStreamCommands.XClaimOptions options) { + + XClaimParams params = XClaimParams.xClaimParams(); + + if (options.isForce()) { + params.force(); + } + + if (options.getRetryCount() != null) { + params.retryCount(options.getRetryCount().intValue()); + } + + if (options.getUnixTime() != null) { + params.time(options.getUnixTime().toEpochMilli()); + } + + return params; + } + + public static XReadParams toXReadParams(StreamReadOptions readOptions) { + + XReadParams params = XReadParams.xReadParams(); + + if (readOptions.isBlocking()) { + params.block(readOptions.getBlock().intValue()); + } + + if (readOptions.getCount() != null) { + params.count(readOptions.getCount().intValue()); + } + + return params; + } + + public static XReadGroupParams toXReadGroupParams(StreamReadOptions readOptions) { + + XReadGroupParams params = XReadGroupParams.xReadGroupParams(); + + if (readOptions.isBlocking()) { + params.block(readOptions.getBlock().intValue()); + } + + if (readOptions.getCount() != null) { + params.count(readOptions.getCount().intValue()); + } + + if (readOptions.isNoack()) { + params.noAck(); + } + + return params; + + } + + public static XPendingParams toXPendingParams(RedisStreamCommands.XPendingOptions options) { + + Range range = (Range) options.getRange(); + XPendingParams xPendingParams = XPendingParams.xPendingParams(StreamConverters.getLowerValue(range), + StreamConverters.getUpperValue(range), options.getCount().intValue()); + + if (options.hasConsumer()) { + xPendingParams.consumer(options.getConsumerName()); + } + + return xPendingParams; + } + } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java index 4579182d33..1d4ee45b76 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java @@ -26,6 +26,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -110,7 +111,7 @@ class ClusterConnectionProvider implements LettuceConnectionProvider, RedisClien } return LettuceFutureUtils - .failed(new UnsupportedOperationException("Connection type " + connectionType + " not supported!")); + .failed(new InvalidDataAccessApiUsageException("Connection type " + connectionType + " not supported!")); } @Override 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 80ed1893ab..f34c266b98 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 @@ -24,6 +24,7 @@ import java.util.Set; import java.util.concurrent.ThreadLocalRandom; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.SortParameters; @@ -134,7 +135,7 @@ public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { @Override public Boolean move(byte[] key, int dbIndex) { - throw new UnsupportedOperationException("MOVE not supported in CLUSTER mode!"); + throw new InvalidDataAccessApiUsageException("MOVE not supported in CLUSTER mode!"); } @Nullable diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index a40de2718c..62e612e985 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -547,7 +547,7 @@ public void multi() { public void select(int dbIndex) { if (asyncSharedConn != null) { - throw new UnsupportedOperationException("Selecting a new database not supported due to shared connection. " + throw new InvalidDataAccessApiUsageException("Selecting a new database not supported due to shared connection. " + "Use separate ConnectionFactorys to work with multiple databases"); } @@ -578,7 +578,7 @@ public void unwatch() { @Override public void watch(byte[]... keys) { if (isQueueing()) { - throw new UnsupportedOperationException(); + throw new InvalidDataAccessApiUsageException("WATCH is not supported when a transaction is active"); } try { if (isPipelined()) { @@ -620,7 +620,8 @@ public void pSubscribe(MessageListener listener, byte[]... patterns) { checkSubscription(); if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("Transaction/Pipelining is not supported for Pub/Sub subscriptions!"); + throw new InvalidDataAccessApiUsageException( + "Transaction/Pipelining is not supported for Pub/Sub subscriptions!"); } try { @@ -637,7 +638,8 @@ public void subscribe(MessageListener listener, byte[]... channels) { checkSubscription(); if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("Transaction/Pipelining is not supported for Pub/Sub subscriptions!"); + throw new InvalidDataAccessApiUsageException( + "Transaction/Pipelining is not supported for Pub/Sub subscriptions!"); } try { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java index 58e85c4c15..0053487bab 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java @@ -25,6 +25,7 @@ import java.util.Map.Entry; import java.util.Set; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisHashCommands; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.core.Cursor; @@ -223,7 +224,7 @@ public Cursor> hScan(byte[] key, long cursorId, ScanOption protected ScanIteration> doScan(byte[] key, long cursorId, ScanOptions options) { if (connection.isQueueing() || connection.isPipelined()) { - throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'HSCAN' cannot be called in pipeline / transaction mode."); } io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); 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 30a7998991..22942e1de6 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 @@ -28,6 +28,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.RedisKeyCommands; import org.springframework.data.redis.connection.SortParameters; @@ -149,7 +150,7 @@ private Cursor doScan(ScanOptions options) { protected LettuceScanIteration doScan(ScanCursor cursor, ScanOptions options) { if (connection.isQueueing() || connection.isPipelined()) { - throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'SCAN' cannot be called in pipeline / transaction mode."); } ScanArgs scanArgs = LettuceConverters.toScanArgs(options); 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 6298a1b448..afb463b27b 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 @@ -24,6 +24,8 @@ import java.util.List; import org.reactivestreams.Publisher; + +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.ReactiveClusterKeyCommands; @@ -122,6 +124,6 @@ public Flux> renameNX(Publisher co @Override public Flux> move(Publisher commands) { - throw new UnsupportedOperationException("MOVE not supported in CLUSTER mode!"); + throw new InvalidDataAccessApiUsageException("MOVE not supported in CLUSTER mode!"); } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java index 2ef2b653dd..4f31ae2f46 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java @@ -21,6 +21,7 @@ import java.util.List; import org.springframework.core.convert.converter.Converter; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisScriptingCommands; import org.springframework.data.redis.connection.ReturnType; import org.springframework.util.Assert; @@ -46,7 +47,7 @@ public void scriptFlush() { public void scriptKill() { if (connection.isQueueing()) { - throw new UnsupportedOperationException("Script kill not permitted in a transaction"); + throw new InvalidDataAccessApiUsageException("Script kill not permitted in a transaction"); } connection.invoke().just(RedisScriptingAsyncCommands::scriptKill); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java index ba7dc72d6d..1a5c4e42c6 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java @@ -26,6 +26,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisServerCommands; import org.springframework.data.redis.core.types.RedisClientInfo; @@ -192,11 +193,6 @@ public String getClientName() { @Override public List getClientList() { - - if (connection.isPipelined()) { - throw new UnsupportedOperationException("Cannot be called in pipeline mode."); - } - return connection.invoke().from(RedisServerAsyncCommands::clientList) .get(LettuceConverters.stringToRedisClientListConverter()); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java index 474d0d040a..6a69fd3511 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Set; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisSetCommands; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; @@ -220,7 +221,7 @@ public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { if (connection.isQueueing() || connection.isPipelined()) { - throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'SSCAN' cannot be called in pipeline / transaction mode."); } io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java index 57ecbddb97..a399924fe3 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Range; import org.springframework.data.redis.connection.BitFieldSubCommands; import org.springframework.data.redis.connection.RedisStringCommands; @@ -275,7 +276,7 @@ public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { Assert.notNull(destination, "Destination key must not be null!"); if (op == BitOperation.NOT && keys.length > 1) { - throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); + throw new IllegalArgumentException("Bitop NOT should only be performed against one key"); } return connection.invoke().just(it -> { @@ -289,7 +290,7 @@ public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { return it.bitopXor(destination, keys); case NOT: if (keys.length != 1) { - throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); + throw new IllegalArgumentException("Bitop NOT should only be performed against one key"); } return it.bitopNot(destination, keys[0]); default: diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java index 14614056b0..d57746f64e 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java @@ -27,6 +27,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs.Flag; import org.springframework.data.redis.connection.convert.Converters; @@ -546,7 +547,7 @@ public Cursor zScan(byte[] key, long cursorId, ScanOptions options) { protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { if (connection.isQueueing() || connection.isPipelined()) { - throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode."); + throw new InvalidDataAccessApiUsageException("'ZSCAN' cannot be called in pipeline / transaction mode."); } io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/StaticMasterReplicaConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/StaticMasterReplicaConnectionProvider.java index e73b0f9618..c288fec517 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/StaticMasterReplicaConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/StaticMasterReplicaConnectionProvider.java @@ -29,6 +29,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.lang.Nullable; /** diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/StreamConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/StreamConverters.java index 9e6e9df349..b56081eebc 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/StreamConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/StreamConverters.java @@ -25,11 +25,9 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; -import java.util.function.BiFunction; import org.springframework.core.convert.converter.Converter; import org.springframework.data.redis.connection.RedisStreamCommands.XClaimOptions; -import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.data.redis.connection.stream.ByteRecord; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.PendingMessagesSummary; @@ -53,39 +51,6 @@ @SuppressWarnings({ "rawtypes" }) class StreamConverters { - private static final Converter>, List> MESSAGEs_TO_IDs = new ListConverter<>( - messageToIdConverter()); - - private static final BiFunction, String, org.springframework.data.redis.connection.stream.PendingMessages> PENDING_MESSAGES_CONVERTER = ( - source, groupName) -> { - - - List messages = source.stream() - .map(it -> { - - RecordId id = RecordId.of(it.getId()); - Consumer consumer = Consumer.from(groupName, it.getConsumer()); - - return new org.springframework.data.redis.connection.stream.PendingMessage(id, consumer, - Duration.ofMillis(it.getMsSinceLastDelivery()), it.getRedeliveryCount()); - - }).toList(); - - return new org.springframework.data.redis.connection.stream.PendingMessages(groupName, messages); - - }; - - private static final BiFunction PENDING_MESSAGES_SUMMARY_CONVERTER = ( - source, groupName) -> { - - org.springframework.data.domain.Range range = source.getMessageIds().isUnbounded() - ? org.springframework.data.domain.Range.unbounded() - : org.springframework.data.domain.Range.open(source.getMessageIds().getLower().getValue(), - source.getMessageIds().getUpper().getValue()); - - return new PendingMessagesSummary(groupName, source.getCount(), range, source.getConsumerMessageCount()); - }; - /** * Convert {@link StreamReadOptions} to Lettuce's {@link XReadArgs}. * @@ -126,7 +91,18 @@ static Converter, RecordId> messageToIdConverter() */ static org.springframework.data.redis.connection.stream.PendingMessages toPendingMessages(String groupName, org.springframework.data.domain.Range range, List source) { - return PENDING_MESSAGES_CONVERTER.apply(source, groupName).withinRange(range); + + List messages = source.stream().map(it -> { + + RecordId id = RecordId.of(it.getId()); + Consumer consumer = Consumer.from(groupName, it.getConsumer()); + + return new org.springframework.data.redis.connection.stream.PendingMessage(id, consumer, + Duration.ofMillis(it.getMsSinceLastDelivery()), it.getRedeliveryCount()); + + }).toList(); + + return new org.springframework.data.redis.connection.stream.PendingMessages(groupName, messages).withinRange(range); } /** @@ -138,7 +114,13 @@ static org.springframework.data.redis.connection.stream.PendingMessages toPendin * @since 2.3 */ static PendingMessagesSummary toPendingMessagesInfo(String groupName, PendingMessages source) { - return PENDING_MESSAGES_SUMMARY_CONVERTER.apply(source, groupName); + + org.springframework.data.domain.Range range = source.getMessageIds().isUnbounded() + ? org.springframework.data.domain.Range.unbounded() + : org.springframework.data.domain.Range.open(source.getMessageIds().getLower().getValue(), + source.getMessageIds().getUpper().getValue()); + + return new PendingMessagesSummary(groupName, source.getCount(), range, source.getConsumerMessageCount()); } /** diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java index dba642ff4c..4b5a67cd4c 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -448,7 +448,7 @@ void testSetAndGet() { } @Test - void testPingPong() { + public void testPingPong() { actual.add(connection.ping()); verifyResults(new ArrayList<>(Collections.singletonList("PONG"))); } @@ -527,7 +527,7 @@ void testBitOpNot() { @Test void testBitOpNotMultipleSources() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> connection.bitOp(BitOperation.NOT, "key3", "key1", "key2")); } @@ -544,7 +544,7 @@ public void testCopy() { } @Test - void testInfo() { + public void testInfo() { actual.add(connection.info()); List results = getResults(); @@ -763,7 +763,7 @@ public void testMultiExec() { } @Test - void testMultiAlreadyInTx() { + public void testMultiAlreadyInTx() { connection.multi(); // Ensure it's OK to call multi twice testMultiExec(); @@ -882,7 +882,7 @@ void testSortStoreNullParams() { } @Test - void testDbSize() { + public void testDbSize() { actual.add(connection.set("dbparam", "foo")); actual.add(connection.dbSize()); @@ -890,7 +890,7 @@ void testDbSize() { } @Test - void testFlushDb() { + public void testFlushDb() { connection.flushDb(); actual.add(connection.dbSize()); verifyResults(Arrays.asList(new Object[] { 0L })); @@ -905,7 +905,7 @@ public void testGetConfig() { } @Test - void testEcho() { + public void testEcho() { actual.add(connection.echo("Hello World")); verifyResults(Arrays.asList(new Object[] { "Hello World" })); } @@ -2525,14 +2525,14 @@ public void testMove() { } @Test - void testLastSave() { + public void testLastSave() { actual.add(connection.lastSave()); List results = getResults(); assertThat(results.get(0)).isNotNull(); } @Test // DATAREDIS-206, DATAREDIS-513 - void testGetTimeShouldRequestServerTime() { + public void testGetTimeShouldRequestServerTime() { actual.add(connection.time()); @@ -2543,7 +2543,7 @@ void testGetTimeShouldRequestServerTime() { } @Test // GH-526 - void testGetTimeShouldRequestServerTimeAsMicros() { + public void testGetTimeShouldRequestServerTimeAsMicros() { actual.add(connection.time(TimeUnit.MICROSECONDS)); actual.add(connection.time(TimeUnit.SECONDS)); @@ -2629,21 +2629,17 @@ void scanWithType() { connection.lPush("list", "foo"); connection.sAdd("set", "foo"); - try (Cursor cursor = connection.scan(KeyScanOptions.scanOptions().type("set").build())) { - assertThat(toList(cursor)).hasSize(1).contains("set"); - } + Cursor cursor = connection.scan(KeyScanOptions.scanOptions().type("set").build()); + assertThat(toList(cursor)).hasSize(1).contains("set"); - try (Cursor cursor = connection.scan(KeyScanOptions.scanOptions().type("string").match("k*").build())) { - assertThat(toList(cursor)).hasSize(1).contains("key"); - } + cursor = connection.scan(KeyScanOptions.scanOptions().type("string").match("k*").build()); + assertThat(toList(cursor)).hasSize(1).contains("key"); - try (Cursor cursor = connection.scan(KeyScanOptions.scanOptions().match("k*").build())) { - assertThat(toList(cursor)).hasSize(1).contains("key"); - } + cursor = connection.scan(KeyScanOptions.scanOptions().match("k*").build()); + assertThat(toList(cursor)).hasSize(1).contains("key"); - try (Cursor cursor = connection.scan(KeyScanOptions.scanOptions().build())) { - assertThat(toList(cursor)).contains("key", "list", "set"); - } + cursor = connection.scan(KeyScanOptions.scanOptions().build()); + assertThat(toList(cursor)).contains("key", "list", "set"); } private static List toList(Cursor cursor) { @@ -2841,7 +2837,7 @@ void zRangeByLexTest() { @SuppressWarnings("unchecked") @Test // DATAREDIS-729 - void zRevRangeByLexTest() { + public void zRevRangeByLexTest() { actual.add(connection.zAdd("myzset", 0, "a")); actual.add(connection.zAdd("myzset", 0, "b")); @@ -3305,7 +3301,6 @@ void geoRadiusByMemberShouldApplyLimit() { @Test // GH-2043 @EnabledOnCommand("GEOSEARCH") - @EnabledOnRedisDriver(RedisDriver.LETTUCE) void geoSearchByMemberShouldReturnMembersCorrectly() { String key = "geo-" + UUID.randomUUID(); @@ -3323,7 +3318,6 @@ void geoSearchByMemberShouldReturnMembersCorrectly() { @Test // GH-2043 @EnabledOnCommand("GEOSEARCH") - @EnabledOnRedisDriver(RedisDriver.LETTUCE) void geoSearchByPointShouldReturnMembersCorrectly() { String key = "geo-" + UUID.randomUUID(); @@ -3341,7 +3335,6 @@ void geoSearchByPointShouldReturnMembersCorrectly() { @Test // GH-2043 @EnabledOnCommand("GEOSEARCH") - @EnabledOnRedisDriver(RedisDriver.LETTUCE) void geoSearchShouldConsiderDistanceCorrectly() { String key = "geo-" + UUID.randomUUID(); @@ -3361,7 +3354,6 @@ void geoSearchShouldConsiderDistanceCorrectly() { @Test // GH-2043 @EnabledOnCommand("GEOSEARCHSTORE") - @EnabledOnRedisDriver(RedisDriver.LETTUCE) void geoSearchStoreByMemberShouldStoreResult() { String key = "geo-" + UUID.randomUUID(); @@ -3381,7 +3373,6 @@ void geoSearchStoreByMemberShouldStoreResult() { @Test // GH-2043 @EnabledOnCommand("GEOSEARCHSTORE") - @EnabledOnRedisDriver(RedisDriver.LETTUCE) void geoSearchStoreByPointShouldStoreResult() { String key = "geo-" + UUID.randomUUID(); @@ -3763,7 +3754,6 @@ public void xRevRangeShouldWorkWithBoundedRange() { @Test // DATAREDIS-1084 @EnabledOnCommand("XADD") - @EnabledOnRedisDriver(RedisDriver.LETTUCE) void xPendingShouldLoadOverviewCorrectly() { actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2))); @@ -3785,7 +3775,6 @@ void xPendingShouldLoadOverviewCorrectly() { @Test // DATAREDIS-1084 @EnabledOnCommand("XADD") - @EnabledOnRedisDriver(RedisDriver.LETTUCE) void xPendingShouldLoadEmptyOverviewCorrectly() { actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2))); diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionTransactionIntegrationTests.java index becb13afdd..7b0f3f9f1a 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionTransactionIntegrationTests.java @@ -23,6 +23,8 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.springframework.dao.InvalidDataAccessApiUsageException; + /** * @author Jennifer Hickey * @author Thomas Darimont @@ -128,14 +130,15 @@ public void testHashNullValue() {} @Test public void testWatchWhileInTx() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> connection.watch("foo".getBytes())); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) + .isThrownBy(() -> connection.watch("foo".getBytes())); } @Test public void testScriptKill() { // Impossible to call script kill in a tx because you can't issue the // exec command while Redis is running a script - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> connection.scriptKill()); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(() -> connection.scriptKill()); } @Test // DATAREDIS-417 diff --git a/src/test/java/org/springframework/data/redis/connection/ClusterSlotHashUtilsTests.java b/src/test/java/org/springframework/data/redis/connection/ClusterSlotHashUtilsTests.java index 49620704f5..c26dac71c4 100644 --- a/src/test/java/org/springframework/data/redis/connection/ClusterSlotHashUtilsTests.java +++ b/src/test/java/org/springframework/data/redis/connection/ClusterSlotHashUtilsTests.java @@ -17,9 +17,9 @@ import static org.assertj.core.api.Assertions.*; +import redis.clients.jedis.ConnectionPool; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; import java.util.Random; @@ -47,8 +47,8 @@ public ClusterSlotHashUtilsTests(JedisCluster cluster) { @Test void localCalculationShouldMatchServers() { - JedisPool pool = cluster.getClusterNodes().values().iterator().next(); - Jedis jedis = pool.getResource(); + ConnectionPool pool = cluster.getClusterNodes().values().iterator().next(); + Jedis jedis = new Jedis(pool.getResource()); for (int i = 0; i < 100; i++) { String key = randomString(); @@ -66,8 +66,8 @@ void localCalculationShouldMatchServers() { @Test void localCalculationShoudMatchServersForPrefixedKeys() { - JedisPool pool = cluster.getClusterNodes().values().iterator().next(); - Jedis jedis = pool.getResource(); + ConnectionPool pool = cluster.getClusterNodes().values().iterator().next(); + Jedis jedis = new Jedis(pool.getResource()); for (int i = 0; i < 100; i++) { String slotPrefix = "{" + randomString() + "}"; 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 6c5606aebc..7a4c82400e 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 @@ -27,10 +27,10 @@ import static org.springframework.data.redis.connection.RedisZSetCommands.*; import static org.springframework.data.redis.core.ScanOptions.*; +import redis.clients.jedis.ConnectionPool; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; import java.io.IOException; import java.nio.charset.Charset; @@ -121,8 +121,8 @@ public JedisClusterConnectionTests(JedisCluster nativeConnection) { @BeforeEach void tearDown() throws IOException { - for (JedisPool pool : nativeConnection.getClusterNodes().values()) { - try (Jedis jedis = pool.getResource()) { + for (ConnectionPool pool : nativeConnection.getClusterNodes().values()) { + try (Jedis jedis = new Jedis(pool.getResource())) { jedis.flushAll(); } catch (Exception e) { // ignore this one since we cannot remove data from replicas @@ -372,7 +372,8 @@ public void dumpAndRestoreWithReplaceOptionShouldWorkCorrectly() { @Test // DATAREDIS-315 public void echoShouldReturnInputCorrectly() { - assertThat(clusterConnection.echo(VALUE_1_BYTES)).isEqualTo(VALUE_1_BYTES); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) + .isThrownBy(() -> clusterConnection.echo(VALUE_1_BYTES)); } @Test // DATAREDIS-315 @@ -1367,7 +1368,7 @@ public void mSetShouldWorkWhenKeysMapToSameSlot() { @Test // DATAREDIS-315 public void moveShouldNotBeSupported() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> clusterConnection.move(KEY_1_BYTES, 3)); } @@ -1986,7 +1987,7 @@ public void setWithExpirationInMillisecondsShouldWorkCorrectly() { clusterConnection.set(KEY_1_BYTES, VALUE_1_BYTES, Expiration.milliseconds(500), SetOption.upsert()); assertThat(nativeConnection.exists(KEY_1_BYTES)).isTrue(); - assertThat(nativeConnection.pttl(KEY_1).doubleValue()).isCloseTo(500d, offset(499d)); + assertThat(nativeConnection.pttl(KEY_1)).isCloseTo(500L, offset(499L)); } @Test // DATAREDIS-316 @@ -2870,7 +2871,8 @@ void evelShaShouldRunScript() { void lPos() { nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c"); - List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, null); + List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, + null); assertThat(result).containsOnly(2L); } @@ -2880,7 +2882,8 @@ void lPos() { void lPosRank() { nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c"); - List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), 2, null); + List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), 2, + null); assertThat(result).containsExactly(6L); } @@ -2890,7 +2893,8 @@ void lPosRank() { void lPosNegativeRank() { nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c"); - List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), -1, null); + List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), -1, + null); assertThat(result).containsExactly(7L); } @@ -2900,7 +2904,8 @@ void lPosNegativeRank() { void lPosCount() { nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c"); - List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, 2); + List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, + 2); assertThat(result).containsExactly(2L, 6L); } @@ -2920,7 +2925,8 @@ void lPosRankCount() { void lPosCountZero() { nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c"); - List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, 0); + List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "c".getBytes(StandardCharsets.UTF_8), null, + 0); assertThat(result).containsExactly(2L, 6L, 7L); } @@ -2930,7 +2936,8 @@ void lPosCountZero() { void lPosNonExisting() { nativeConnection.rpush(KEY_1, "a", "b", "c", "1", "2", "3", "c", "c"); - List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "x".getBytes(StandardCharsets.UTF_8), null, null); + List result = clusterConnection.listCommands().lPos(KEY_1_BYTES, "x".getBytes(StandardCharsets.UTF_8), null, + null); assertThat(result).isEmpty(); } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java deleted file mode 100644 index 10ff91ebf4..0000000000 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright 2015-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.redis.connection.jedis; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; -import static org.springframework.data.redis.connection.ClusterTestVariables.*; -import static org.springframework.data.redis.test.util.MockitoUtils.*; - -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisClusterConnectionHandler; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.exceptions.JedisConnectionException; - -import java.io.IOException; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.Spy; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; -import org.mockito.stubbing.Answer; - -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.data.redis.ClusterStateFailureException; -import org.springframework.data.redis.RedisSystemException; -import org.springframework.data.redis.connection.ClusterInfo; -import org.springframework.data.redis.connection.RedisClusterCommands.AddSlots; -import org.springframework.data.redis.connection.RedisClusterNode; -import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisClusterTopologyProvider; - -/** - * @author Christoph Strobl - * @author Mark Paluch - * @author Chen Guanqun - */ -@ExtendWith(MockitoExtension.class) -@MockitoSettings(strictness = Strictness.LENIENT) -class JedisClusterConnectionUnitTests { - - private static final String CLUSTER_NODES_RESPONSE = "" // - + MASTER_NODE_1_ID + " " + CLUSTER_HOST + ":" + MASTER_NODE_1_PORT + " myself,master - 0 0 1 connected 0-5460" - + "\n" + MASTER_NODE_2_ID + " " + CLUSTER_HOST + ":" + MASTER_NODE_2_PORT - + " master - 0 1427718161587 2 connected 5461-10922" + "\n" + MASTER_NODE_2_ID + " " + CLUSTER_HOST + ":" - + MASTER_NODE_3_PORT + " master - 0 1427718161587 3 connected 10923-16383"; - - private static final String CLUSTER_INFO_RESPONSE = "cluster_state:ok" + "\n" + "cluster_slots_assigned:16384" + "\n" - + "cluster_slots_ok:16384" + "\n" + "cluster_slots_pfail:0" + "\n" + "cluster_slots_fail:0" + "\n" - + "cluster_known_nodes:4" + "\n" + "cluster_size:3" + "\n" + "cluster_current_epoch:30" + "\n" - + "cluster_my_epoch:2" + "\n" + "cluster_stats_messages_sent:2560260" + "\n" - + "cluster_stats_messages_received:2560086"; - - private JedisClusterConnection connection; - - @Spy StubJedisCluster clusterMock; - @Mock JedisClusterConnectionHandler connectionHandlerMock; - - @Mock JedisPool node1PoolMock; - @Mock JedisPool node2PoolMock; - @Mock JedisPool node3PoolMock; - - @Mock Jedis con1Mock; - @Mock Jedis con2Mock; - @Mock Jedis con3Mock; - - private Map nodes = new LinkedHashMap<>(); - - @BeforeEach - void setUp() { - - nodes.put(CLUSTER_HOST + ":" + MASTER_NODE_1_PORT, node1PoolMock); - nodes.put(CLUSTER_HOST + ":" + MASTER_NODE_2_PORT, node2PoolMock); - nodes.put(CLUSTER_HOST + ":" + MASTER_NODE_3_PORT, node3PoolMock); - - when(clusterMock.getClusterNodes()).thenReturn(nodes); - when(node1PoolMock.getResource()).thenReturn(con1Mock); - when(node2PoolMock.getResource()).thenReturn(con2Mock); - when(node3PoolMock.getResource()).thenReturn(con3Mock); - - when(con1Mock.clusterNodes()).thenReturn(CLUSTER_NODES_RESPONSE); - when(con2Mock.clusterNodes()).thenReturn(CLUSTER_NODES_RESPONSE); - when(con3Mock.clusterNodes()).thenReturn(CLUSTER_NODES_RESPONSE); - clusterMock.setConnectionHandler(connectionHandlerMock); - - connection = new JedisClusterConnection(clusterMock); - } - - @Test // DATAREDIS-315 - void throwsExceptionWhenClusterCommandExecutorIsNull() { - assertThatIllegalArgumentException().isThrownBy(() -> new JedisClusterConnection(clusterMock, null)); - } - - @Test // DATAREDIS-315 - void clusterMeetShouldSendCommandsToExistingNodesCorrectly() { - - connection.clusterMeet(UNKNOWN_CLUSTER_NODE); - - verify(con1Mock, times(1)).clusterMeet(UNKNOWN_CLUSTER_NODE.getHost(), UNKNOWN_CLUSTER_NODE.getPort()); - verify(con2Mock, times(1)).clusterMeet(UNKNOWN_CLUSTER_NODE.getHost(), UNKNOWN_CLUSTER_NODE.getPort()); - verify(con2Mock, times(1)).clusterMeet(UNKNOWN_CLUSTER_NODE.getHost(), UNKNOWN_CLUSTER_NODE.getPort()); - } - - @Test // DATAREDIS-315 - void clusterMeetShouldThrowExceptionWhenNodeIsNull() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.clusterMeet(null)); - } - - @Test // DATAREDIS-315, DATAREDIS-890 - void clusterForgetShouldSendCommandsToRemainingNodesCorrectly() { - - connection.clusterForget(CLUSTER_NODE_2); - - verify(con1Mock, times(1)).clusterForget(CLUSTER_NODE_2.getId()); - verify(con3Mock, times(1)).clusterForget(CLUSTER_NODE_2.getId()); - } - - @Test // DATAREDIS-315, DATAREDIS-890 - void clusterReplicateShouldSendCommandsCorrectly() { - - connection.clusterReplicate(CLUSTER_NODE_1, CLUSTER_NODE_2); - - verify(con2Mock, times(1)).clusterReplicate(CLUSTER_NODE_1.getId()); - verify(con1Mock, atMost(1)).clusterNodes(); - verify(con1Mock, atMost(1)).close(); - verifyNoMoreInteractions(con1Mock); - } - - @Test // DATAREDIS-315 - void closeShouldNotCloseUnderlyingClusterPool() throws IOException { - - connection.close(); - - verify(clusterMock, never()).close(); - } - - @Test // DATAREDIS-315 - void isClosedShouldReturnConnectionStateCorrectly() { - - assertThat(connection.isClosed()).isFalse(); - - connection.close(); - - assertThat(connection.isClosed()).isTrue(); - } - - @Test // DATAREDIS-315 - void clusterInfoShouldBeReturnedCorrectly() { - - when(con1Mock.clusterInfo()).thenReturn(CLUSTER_INFO_RESPONSE); - when(con2Mock.clusterInfo()).thenReturn(CLUSTER_INFO_RESPONSE); - when(con3Mock.clusterInfo()).thenReturn(CLUSTER_INFO_RESPONSE); - - ClusterInfo p = connection.clusterGetClusterInfo(); - assertThat(p.getSlotsAssigned()).isEqualTo(16384L); - - verifyInvocationsAcross("clusterInfo", times(1), con1Mock, con2Mock, con3Mock); - } - - @Test // DATAREDIS-315 - void clusterSetSlotImportingShouldBeExecutedCorrectly() { - - connection.clusterSetSlot(CLUSTER_NODE_1, 100, AddSlots.IMPORTING); - - verify(con1Mock, times(1)).clusterSetSlotImporting(eq(100), eq(CLUSTER_NODE_1.getId())); - } - - @Test // DATAREDIS-315 - void clusterSetSlotMigratingShouldBeExecutedCorrectly() { - - connection.clusterSetSlot(CLUSTER_NODE_1, 100, AddSlots.MIGRATING); - - verify(con1Mock, times(1)).clusterSetSlotMigrating(eq(100), eq(CLUSTER_NODE_1.getId())); - } - - @Test // DATAREDIS-315 - void clusterSetSlotStableShouldBeExecutedCorrectly() { - - connection.clusterSetSlot(CLUSTER_NODE_1, 100, AddSlots.STABLE); - - verify(con1Mock, times(1)).clusterSetSlotStable(eq(100)); - } - - @Test // DATAREDIS-315 - void clusterSetSlotNodeShouldBeExecutedCorrectly() { - - connection.clusterSetSlot(CLUSTER_NODE_1, 100, AddSlots.NODE); - - verify(con1Mock, times(1)).clusterSetSlotNode(eq(100), eq(CLUSTER_NODE_1.getId())); - } - - @Test // DATAREDIS-315 - void clusterSetSlotShouldBeExecutedOnTargetNodeWhenNodeIdNotSet() { - - connection.clusterSetSlot(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_2_PORT), 100, AddSlots.IMPORTING); - - verify(con2Mock, times(1)).clusterSetSlotImporting(eq(100), eq(CLUSTER_NODE_2.getId())); - } - - @Test // DATAREDIS-315 - void clusterSetSlotShouldThrowExceptionWhenModeIsNull() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.clusterSetSlot(CLUSTER_NODE_1, 100, null)); - } - - @Test // DATAREDIS-315 - void clusterDeleteSlotsShouldBeExecutedCorrectly() { - - int[] slots = new int[] { 9000, 10000 }; - connection.clusterDeleteSlots(CLUSTER_NODE_2, slots); - - verify(con2Mock, times(1)).clusterDelSlots((int[]) any()); - } - - @Test // DATAREDIS-315 - void clusterDeleteSlotShouldThrowExceptionWhenNodeIsNull() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.clusterDeleteSlots(null, new int[] { 1 })); - } - - @Test // DATAREDIS-315 - void timeShouldBeExecutedOnArbitraryNode() { - - List values = Arrays.asList("1449655759", "92217"); - when(con1Mock.time()).thenReturn(values); - when(con2Mock.time()).thenReturn(values); - when(con3Mock.time()).thenReturn(values); - - connection.time(); - - verifyInvocationsAcross("time", times(1), con1Mock, con2Mock, con3Mock); - } - - @Test // DATAREDIS-679 - void shouldFailWithUnknownNode() { - - try { - connection.serverCommands().dbSize(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT)); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage()) - .contains("Node " + CLUSTER_HOST + ":" + REPLICAOF_NODE_1_PORT + " is unknown to cluster"); - } - } - - @Test // DATAREDIS-679 - void shouldFailWithAbsentConnection() { - - nodes.remove(CLUSTER_HOST + ":" + MASTER_NODE_3_PORT); - - assertThatExceptionOfType(DataAccessResourceFailureException.class) - .isThrownBy(() -> connection.serverCommands().dbSize(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT))) - .withMessageContaining("Node " + CLUSTER_HOST + ":" + MASTER_NODE_3_PORT + " is unknown to cluster"); - } - - @Test // DATAREDIS-679 - void shouldReconfigureJedisWithDiscoveredNode() { - - nodes.remove(CLUSTER_HOST + ":" + MASTER_NODE_3_PORT); - - when(connectionHandlerMock.getConnectionFromNode(new HostAndPort(CLUSTER_HOST, MASTER_NODE_3_PORT))) - .thenReturn(con3Mock); - when(con3Mock.dbSize()).thenAnswer(new Answer() { - - @Override - public Long answer(InvocationOnMock invocation) throws Throwable { - - // Required to return the resource properly after invocation. - nodes.put(CLUSTER_HOST + ":" + MASTER_NODE_3_PORT, node3PoolMock); - - return 42L; - } - }); - - Long result = connection.serverCommands().dbSize(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)); - - assertThat(result).isEqualTo(42L); - } - - @Test // DATAREDIS-315, DATAREDIS-890 - void timeShouldBeExecutedOnSingleNode() { - - when(con2Mock.time()).thenReturn(Arrays.asList("1449655759", "92217")); - - connection.time(CLUSTER_NODE_2); - - verify(con2Mock, times(1)).time(); - verify(con2Mock, atLeast(1)).close(); - verify(con1Mock, atMost(1)).clusterNodes(); - verify(con1Mock, atMost(1)).close(); - - } - - @Test // DATAREDIS-315 - void resetConfigStatsShouldBeExecutedOnAllNodes() { - - connection.resetConfigStats(); - - verify(con1Mock, times(1)).configResetStat(); - verify(con2Mock, times(1)).configResetStat(); - verify(con3Mock, times(1)).configResetStat(); - } - - @Test // DATAREDIS-315, DATAREDIS-890 - void resetConfigStatsShouldBeExecutedOnSingleNodeCorrectly() { - - connection.resetConfigStats(CLUSTER_NODE_2); - - verify(con2Mock, times(1)).configResetStat(); - verify(con2Mock, atLeast(1)).close(); - verify(con1Mock, never()).configResetStat(); - verify(con3Mock, never()).configResetStat(); - } - - @Test // GH-1992 - void rewriteConfigShouldBeExecutedOnAllNodes() { - - connection.rewriteConfig(); - - verify(con1Mock, times(1)).configRewrite(); - verify(con2Mock, times(1)).configRewrite(); - verify(con3Mock, times(1)).configRewrite(); - } - - @Test // GH-1992 - void rewriteConfigShouldBeExecutedOnSingleNodeCorrectly() { - - connection.rewriteConfig(CLUSTER_NODE_2); - - verify(con2Mock, times(1)).configRewrite(); - verify(con2Mock, atLeast(1)).close(); - verify(con1Mock, never()).configRewrite(); - verify(con3Mock, never()).configRewrite(); - } - - @Test // DATAREDIS-315 - void clusterTopologyProviderShouldCollectErrorsWhenLoadingNodes() { - - when(con1Mock.clusterNodes()).thenThrow(new JedisConnectionException("o.O")); - when(con2Mock.clusterNodes()).thenThrow(new JedisConnectionException("o.1")); - when(con3Mock.clusterNodes()).thenThrow(new JedisConnectionException("o.2")); - - assertThatExceptionOfType(ClusterStateFailureException.class) - .isThrownBy(() -> new JedisClusterTopologyProvider(clusterMock).getTopology()) - .withMessageContaining("127.0.0.1:7379 failed: o.O").withMessageContaining("127.0.0.1:7380 failed: o.1"); - } - - @Test // DATAREDIS-603 - void translatesUnknownExceptions() { - - IllegalArgumentException exception = new IllegalArgumentException("Aw, snap!"); - - doThrow(exception).when(clusterMock).set("foo".getBytes(), "bar".getBytes()); - - assertThatExceptionOfType(RedisSystemException.class) - .isThrownBy(() -> connection.set("foo".getBytes(), "bar".getBytes())) - .withMessageContaining(exception.getMessage()).withCause(exception); - } - - @Test // DATAREDIS-794 - void clusterTopologyProviderShouldUseCachedTopology() { - - when(clusterMock.getClusterNodes()).thenReturn(Collections.singletonMap("mock", node1PoolMock)); - when(con1Mock.clusterNodes()).thenReturn(CLUSTER_NODES_RESPONSE); - - JedisClusterTopologyProvider provider = new JedisClusterTopologyProvider(clusterMock, Duration.ofSeconds(5)); - provider.getTopology(); - provider.getTopology(); - - verify(con1Mock).clusterNodes(); - } - - @Test // DATAREDIS-794 - void clusterTopologyProviderShouldRequestTopology() { - - when(clusterMock.getClusterNodes()).thenReturn(Collections.singletonMap("mock", node1PoolMock)); - when(con1Mock.clusterNodes()).thenReturn(CLUSTER_NODES_RESPONSE); - - JedisClusterTopologyProvider provider = new JedisClusterTopologyProvider(clusterMock, Duration.ZERO); - provider.getTopology(); - provider.getTopology(); - - verify(con1Mock, times(2)).clusterNodes(); - } - - @Test // GH-1985 - void nodeWithoutHostShouldRejectConnectionAttempt() { - - reset(con1Mock, con2Mock, con3Mock); - - when(con1Mock.clusterNodes()) - .thenReturn("ef570f86c7b1a953846668debc177a3a16733420 :6379 fail,master - 0 0 1 connected"); - when(con2Mock.clusterNodes()) - .thenReturn("ef570f86c7b1a953846668debc177a3a16733420 :6379 fail,master - 0 0 1 connected"); - when(con3Mock.clusterNodes()) - .thenReturn("ef570f86c7b1a953846668debc177a3a16733420 :6379 fail,master - 0 0 1 connected"); - - JedisClusterConnection connection = new JedisClusterConnection(clusterMock); - - assertThatThrownBy(() -> connection.ping(new RedisClusterNode("ef570f86c7b1a953846668debc177a3a16733420"))) - .isInstanceOf(DataAccessResourceFailureException.class) - .hasMessageContaining("ef570f86c7b1a953846668debc177a3a16733420"); - } - - static class StubJedisCluster extends JedisCluster { - - JedisClusterConnectionHandler connectionHandler; - - public StubJedisCluster() { - super(Collections.emptySet()); - } - - JedisClusterConnectionHandler getConnectionHandler() { - return connectionHandler; - } - - void setConnectionHandler(JedisClusterConnectionHandler connectionHandler) { - this.connectionHandler = connectionHandler; - } - } -} diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java index 569674221f..b64f3ed2e8 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java @@ -20,8 +20,6 @@ import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisClusterConnectionHandler; -import redis.clients.jedis.JedisClusterInfoCache; import redis.clients.jedis.JedisPoolConfig; import java.io.IOException; @@ -29,7 +27,6 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; @@ -39,7 +36,6 @@ import org.junit.jupiter.api.Test; import org.springframework.data.redis.connection.RedisClusterConfiguration; -import org.springframework.data.redis.connection.RedisClusterConnection; import org.springframework.data.redis.connection.RedisPassword; import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; @@ -95,8 +91,7 @@ void shouldInitConnectionCorrectlyWhenClusterConfigPresent() { connectionFactory = initSpyedConnectionFactory(CLUSTER_CONFIG, new JedisPoolConfig()); connectionFactory.afterPropertiesSet(); - verify(connectionFactory, times(1)).createCluster(eq(CLUSTER_CONFIG), - any(GenericObjectPoolConfig.class)); + verify(connectionFactory, times(1)).createCluster(eq(CLUSTER_CONFIG), any(GenericObjectPoolConfig.class)); verify(connectionFactory, never()).createRedisPool(); } @@ -307,50 +302,6 @@ void shouldReturnClusterConfiguration() { assertThat(connectionFactory.getClusterConfiguration()).isSameAs(configuration); } - @Test // DATAREDIS-974, GH-2017 - void shouldApplySslConfigWhenCreatingClusterClient() throws NoSuchAlgorithmException { - - SSLParameters sslParameters = new SSLParameters(); - SSLContext context = SSLContext.getDefault(); - SSLSocketFactory socketFactory = context.getSocketFactory(); - JedisPoolConfig poolConfig = new JedisPoolConfig(); - HostnameVerifier hostNameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); - - JedisClientConfiguration configuration = JedisClientConfiguration.builder() // - .useSsl() // - .hostnameVerifier(hostNameVerifier) // - .sslParameters(sslParameters) // - .sslSocketFactory(socketFactory).and() // - .clientName("my-client") // - .connectTimeout(Duration.ofMinutes(1)) // - .readTimeout(Duration.ofMinutes(5)) // - .usePooling().poolConfig(poolConfig) // - .build(); - - connectionFactory = new JedisConnectionFactory(new RedisClusterConfiguration(), configuration); - connectionFactory.afterPropertiesSet(); - - RedisClusterConnection connection = connectionFactory.getClusterConnection(); - assertThat(connection).isInstanceOf(JedisClusterConnection.class); - - JedisCluster cluster = ((JedisClusterConnection) connection).getCluster(); - - JedisClusterConnectionHandler connectionHandler = (JedisClusterConnectionHandler) ReflectionTestUtils - .getField(cluster, "connectionHandler"); - JedisClusterInfoCache cache = (JedisClusterInfoCache) ReflectionTestUtils.getField(connectionHandler, "cache"); - JedisClientConfig clientConfig = (JedisClientConfig) ReflectionTestUtils.getField(cache, "clientConfig"); - - assertThat(clientConfig.getConnectionTimeoutMillis()).isEqualTo(60000); - assertThat(clientConfig.getSocketTimeoutMillis()).isEqualTo(300000); - assertThat(clientConfig.getPassword()).isNull(); - assertThat(clientConfig.getClientName()).isEqualTo("my-client"); - assertThat(clientConfig.isSsl()).isEqualTo(true); - assertThat(clientConfig.getSslSocketFactory()).isEqualTo(socketFactory); - assertThat(clientConfig.getSslParameters()).isEqualTo(sslParameters); - assertThat(clientConfig.getHostnameVerifier()).isEqualTo(hostNameVerifier); - assertThat(clientConfig.getHostAndPortMapper()).isNull(); - } - @Test // DATAREDIS-574 void shouldDenyChangesToImmutableClientConfiguration() throws NoSuchAlgorithmException { diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java index 69b8c7eaf9..76c292951a 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java @@ -178,8 +178,7 @@ public void testRestoreBadData() { @Test @Disabled - public void testRestoreExistingKey() { - } + public void testRestoreExistingKey() {} @Test public void testExecWithoutMulti() { diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java index 48d3f2b5a1..4852afc81c 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java @@ -19,19 +19,15 @@ import redis.clients.jedis.JedisPoolConfig; -import java.util.Arrays; -import java.util.List; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.SettingsUtils; import org.springframework.data.redis.connection.AbstractConnectionPipelineIntegrationTests; -import org.springframework.data.redis.connection.DefaultStringRedisConnection; import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.test.condition.EnabledOnCommand; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -61,47 +57,6 @@ public void tearDown() { connection = null; } - @Test - public void testWatch() { - connection.set("testitnow", "willdo"); - connection.watch("testitnow".getBytes()); - // Jedis doesn't actually send commands until you close the pipeline - getResults(); - DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(connectionFactory.getConnection()); - conn2.set("testitnow", "something"); - conn2.close(); - // Reopen the pipeline - initConnection(); - connection.multi(); - connection.set("testitnow", "somethingelse"); - actual.add(connection.exec()); - actual.add(connection.get("testitnow")); - verifyResults(Arrays.asList(new Object[] { null, "something" })); - } - - @SuppressWarnings("unchecked") - @Test - public void testUnwatch() throws Exception { - connection.set("testitnow", "willdo"); - connection.watch("testitnow".getBytes()); - // Jedis doesn't actually send commands until you close the pipeline - getResults(); - initConnection(); - connection.unwatch(); - // Jedis doesn't actually send commands until you close the pipeline - getResults(); - initConnection(); - connection.multi(); - DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(connectionFactory.getConnection()); - conn2.set("testitnow", "something"); - connection.set("testitnow", "somethingelse"); - connection.get("testitnow"); - actual.add(connection.exec()); - List results = getResults(); - List execResults = (List) results.get(0); - assertThat(execResults).isEqualTo(Arrays.asList(new Object[] { true, "somethingelse" })); - } - @Test // DATAREDIS-213 - Verify connection returns to pool after select public void testClosePoolPipelinedDbSelect() { @@ -124,17 +79,17 @@ public void testClosePoolPipelinedDbSelect() { // Unsupported Ops @Test public void testScriptLoadEvalSha() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testScriptLoadEvalSha); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testScriptLoadEvalSha); } @Test public void testEvalShaArrayStrings() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalShaArrayStrings); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalShaArrayStrings); } @Test public void testEvalShaArrayBytes() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalShaArrayBytes); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalShaArrayBytes); } @Test @@ -147,67 +102,66 @@ public void testEvalShaArrayError() {} @Test public void testEvalReturnString() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnString); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnString); } @Test public void testEvalReturnNumber() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnNumber); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnNumber); } @Test public void testEvalReturnSingleOK() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnSingleOK); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnSingleOK); } @Test @Disabled - public void testEvalReturnSingleError() { - } + public void testEvalReturnSingleError() {} @Test public void testEvalReturnFalse() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnFalse); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnFalse); } @Test public void testEvalReturnTrue() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnTrue); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnTrue); } @Test public void testEvalReturnArrayStrings() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnArrayStrings); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnArrayStrings); } @Test public void testEvalReturnArrayNumbers() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnArrayNumbers); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnArrayNumbers); } @Test public void testEvalReturnArrayOKs() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnArrayOKs); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnArrayOKs); } @Test public void testEvalReturnArrayFalses() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnArrayFalses); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnArrayFalses); } @Test public void testEvalReturnArrayTrues() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testEvalReturnArrayTrues); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testEvalReturnArrayTrues); } @Test public void testScriptExists() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testScriptExists); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testScriptExists); } @Test public void testScriptKill() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> connection.scriptKill()); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(() -> connection.scriptKill()); } @Test @@ -216,120 +170,100 @@ public void testScriptFlush() {} @Test // DATAREDIS-269 public void clientSetNameWorksCorrectly() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::clientSetNameWorksCorrectly); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::clientSetNameWorksCorrectly); } - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xReadShouldReadMessage() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xReadShouldReadMessage); + // DATAREDIS-268 + public void testListClientsContainsAtLeastOneElement() { + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) + .isThrownBy(super::testListClientsContainsAtLeastOneElement); } - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test // DATAREDIS-296 + @Disabled + public void testExecWithoutMulti() {} + + @Test @Override - public void xReadGroupShouldReadMessage() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xReadGroupShouldReadMessage); - } + @Disabled + public void testMultiExec() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xGroupCreateShouldWorkWithAndWithoutExistingStream() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xGroupCreateShouldWorkWithAndWithoutExistingStream); - } + @Disabled + public void testMultiDiscard() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldLoadPendingMessages() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xPendingShouldLoadPendingMessages); - } + @Disabled + public void testErrorInTx() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldWorkWithBoundedRange() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xPendingShouldWorkWithBoundedRange); - } + @Disabled + public void testWatch() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldLoadPendingMessagesForConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xPendingShouldLoadPendingMessagesForConsumer); - } + @Disabled + public void testUnwatch() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldLoadPendingMessagesForNonExistingConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xPendingShouldLoadPendingMessagesForNonExistingConsumer); - } + @Disabled + public void testMultiAlreadyInTx() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xinfo() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfo); - } + @Disabled + public void testPingPong() {} @Test - @EnabledOnCommand("XADD") @Override - public void xinfoNoGroup() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoNoGroup); - } + @Disabled + public void testFlushDb() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") @Override - public void xinfoGroups() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoGroups); - } + @Disabled + public void testEcho() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") @Override - public void xinfoGroupsNoGroup() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoGroupsNoGroup); - } + @Disabled + public void testInfo() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") @Override - public void xinfoGroupsNoConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoGroupsNoConsumer); - } + @Disabled + public void testInfoBySection() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") @Override - public void xinfoConsumers() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoConsumers); - } + @Disabled + public void testMove() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xinfoConsumersNoConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoConsumersNoConsumer); - } + @Disabled + public void testGetConfig() {} @Test @Override - // DATAREDIS-268 - public void testListClientsContainsAtLeastOneElement() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::testListClientsContainsAtLeastOneElement); - } + @Disabled + public void testLastSave() {} - @Test // DATAREDIS-296 + @Test + @Override @Disabled - public void testExecWithoutMulti() {} + public void testGetTimeShouldRequestServerTime() {} + + @Test + @Override + @Disabled + public void testGetTimeShouldRequestServerTimeAsMicros() {} + + @Test + @Override + @Disabled + public void testDbSize() {} + } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineTxIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineTxIntegrationTests.java deleted file mode 100644 index 329f7320c7..0000000000 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineTxIntegrationTests.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.redis.connection.jedis; - -import static org.assertj.core.api.Assertions.*; - -import java.util.List; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -/** - * @author Jennifer Hickey - * @author Christoph Strobl - */ -public class JedisConnectionPipelineTxIntegrationTests extends JedisConnectionTransactionIntegrationTests { - - @Test - @Disabled - public void testRestoreBadData() {} - - @Test - @Disabled - public void testRestoreExistingKey() {} - - protected void initConnection() { - connection.openPipeline(); - connection.multi(); - } - - @SuppressWarnings("unchecked") - protected List getResults() { - assertThat(connection.exec()).isNull(); - List pipelined = connection.closePipeline(); - // We expect only the results of exec to be in the closed pipeline - assertThat(pipelined.size()).isEqualTo(1); - List txResults = (List) pipelined.get(0); - // Return exec results and this test should behave exactly like its superclass - return txResults; - } - - @Test - @Disabled - public void testListClientsContainsAtLeastOneElement() {} - -} diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java index 1ba0717d8b..ecd0c4ca38 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java @@ -22,9 +22,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.AbstractConnectionTransactionIntegrationTests; import org.springframework.data.redis.connection.ReturnType; -import org.springframework.data.redis.test.condition.EnabledOnCommand; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -61,234 +61,196 @@ public void testGetConfig() {} // Unsupported Ops @Test @Disabled - public void testScriptLoadEvalSha() { - } + public void testScriptLoadEvalSha() {} @Test @Disabled - public void testEvalShaArrayStrings() { - } + public void testEvalShaArrayStrings() {} @Test @Disabled - public void testEvalShaArrayBytes() { - } + public void testEvalShaArrayBytes() {} @Test @Disabled - public void testEvalShaNotFound() { - } + public void testEvalShaNotFound() {} @Test public void testEvalShaArrayError() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> connection.evalSha("notasha", ReturnType.MULTI, 1, "key1", "arg1")); } @Test public void testEvalArrayScriptError() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> connection.eval("return {1,2", ReturnType.MULTI, 1, "foo", "bar")); } @Test @Disabled - public void testEvalReturnString() { - } + public void testEvalReturnString() {} @Test @Disabled - public void testEvalReturnNumber() { - } + public void testEvalReturnNumber() {} @Test @Disabled - public void testEvalReturnSingleOK() { - } + public void testEvalReturnSingleOK() {} @Test @Disabled - public void testEvalReturnSingleError() { - } + public void testEvalReturnSingleError() {} @Test @Disabled - public void testEvalReturnFalse() { - } + public void testEvalReturnFalse() {} @Test @Disabled - public void testEvalReturnTrue() { - } + public void testEvalReturnTrue() {} @Test @Disabled - public void testEvalReturnArrayStrings() { - } + public void testEvalReturnArrayStrings() {} @Test @Disabled - public void testEvalReturnArrayNumbers() { - } + public void testEvalReturnArrayNumbers() {} @Test @Disabled - public void testEvalReturnArrayOKs() { - } + public void testEvalReturnArrayOKs() {} @Test @Disabled - public void testEvalReturnArrayFalses() { - } + public void testEvalReturnArrayFalses() {} @Test @Disabled - public void testEvalReturnArrayTrues() { - } + public void testEvalReturnArrayTrues() {} @Test @Disabled - public void testScriptExists() { - } + public void testScriptExists() {} @Test @Disabled - public void testScriptKill() { - } + public void testScriptKill() {} @Test @Disabled - public void testScriptFlush() { - } + public void testScriptFlush() {} @Test @Disabled - public void testInfoBySection() { - } + public void testInfoBySection() {} @Test @Disabled - public void testRestoreBadData() { - } + public void testRestoreBadData() {} @Test @Disabled - public void testRestoreExistingKey() { - } + public void testRestoreExistingKey() {} @Test // DATAREDIS-269 @Disabled - public void clientSetNameWorksCorrectly() { - } + public void clientSetNameWorksCorrectly() {} @Test @Override // DATAREDIS-268 public void testListClientsContainsAtLeastOneElement() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(super::testListClientsContainsAtLeastOneElement); } - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test // DATAREDIS-296 + @Disabled + public void testExecWithoutMulti() {} + + @Test @Override - public void xReadShouldReadMessage() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xReadShouldReadMessage); - } + @Disabled + public void testMultiExec() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xReadGroupShouldReadMessage() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xReadGroupShouldReadMessage); - } + @Disabled + public void testMultiDiscard() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xGroupCreateShouldWorkWithAndWithoutExistingStream() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xGroupCreateShouldWorkWithAndWithoutExistingStream); - } + @Disabled + public void testErrorInTx() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldLoadPendingMessages() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xPendingShouldLoadPendingMessages); - } + @Disabled + public void testWatch() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldWorkWithBoundedRange() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xPendingShouldWorkWithBoundedRange); - } + @Disabled + public void testUnwatch() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldLoadPendingMessagesForConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xPendingShouldLoadPendingMessagesForConsumer); - } + @Disabled + public void testMultiAlreadyInTx() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xPendingShouldLoadPendingMessagesForNonExistingConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::xPendingShouldLoadPendingMessagesForNonExistingConsumer); - } + @Disabled + public void testPingPong() {} + + @Test + @Override + @Disabled + public void testFlushDb() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") @Override - public void xinfo() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfo); - } + @Disabled + public void testEcho() {} + + @Override + @Disabled + public void testInfo() {} + + @Override + @Disabled + public void testMove() {} @Test - @EnabledOnCommand("XADD") @Override - public void xinfoNoGroup() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoNoGroup); - } + @Disabled + public void testLastSave() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xinfoGroups() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoGroups); - } + @Disabled + public void testGetTimeShouldRequestServerTime() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xinfoGroupsNoGroup() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoGroupsNoGroup); - } + @Disabled + public void testGetTimeShouldRequestServerTimeAsMicros() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xinfoGroupsNoConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoGroupsNoConsumer); - } + @Disabled + public void testDbSize() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xinfoConsumers() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoConsumers); - } + @Disabled + public void testSelect() {} - @Test // GH-1711 - @EnabledOnCommand("XADD") + @Test @Override - public void xinfoConsumersNoConsumer() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::xinfoConsumersNoConsumer); - } + @Disabled("Parameter ordering in zrevrangeByLex(byte[] key, byte[] max, byte[] min) is swapped so transactions use inverse parameter order") + public void zRevRangeByLexTest() {} } 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 256b3d4a12..41cc340319 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,18 +18,19 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; -import redis.clients.jedis.Client; +import redis.clients.jedis.Connection; import redis.clients.jedis.Jedis; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; import redis.clients.jedis.args.SaveMode; import redis.clients.jedis.exceptions.JedisException; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; import java.io.IOException; import java.util.Collections; import java.util.Map.Entry; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -40,7 +41,6 @@ import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; -import org.springframework.test.util.ReflectionTestUtils; /** * @author Christoph Strobl @@ -48,7 +48,7 @@ class JedisConnectionUnitTests { @Nested - public class BasicUnitTests extends AbstractConnectionUnitTestBase { + public class BasicUnitTests extends AbstractConnectionUnitTestBase { protected JedisConnection connection; private Jedis jedisSpy; @@ -56,7 +56,7 @@ public class BasicUnitTests extends AbstractConnectionUnitTestBase { @BeforeEach public void setUp() { - jedisSpy = spy(new MockedClientJedis("http://localhost:1234", getNativeRedisConnectionMock())); + jedisSpy = spy(new Jedis(getNativeRedisConnectionMock())); connection = new JedisConnection(jedisSpy); } @@ -69,7 +69,7 @@ void shutdownWithNullShouldDelegateCommandCorrectly() { // all good. Sometimes it throws an Exception. } - verifyNativeConnectionInvocation().shutdown(); + verify(jedisSpy).shutdown(); } @Test // DATAREDIS-184, GH-2153 @@ -77,7 +77,7 @@ void shutdownNosaveShouldBeSentCorrectly() { assertThatExceptionOfType(JedisException.class).isThrownBy(() -> connection.shutdown(ShutdownOption.NOSAVE)); - verifyNativeConnectionInvocation().shutdown(SaveMode.NOSAVE); + verify(jedisSpy).shutdown(SaveMode.NOSAVE); } @Test // DATAREDIS-184, GH-2153 @@ -85,21 +85,21 @@ void shutdownSaveShouldBeSentCorrectly() { assertThatExceptionOfType(JedisException.class).isThrownBy(() -> connection.shutdown(ShutdownOption.SAVE)); - verifyNativeConnectionInvocation().shutdown(SaveMode.SAVE); + verify(jedisSpy).shutdown(SaveMode.SAVE); } @Test // DATAREDIS-267 public void killClientShouldDelegateCallCorrectly() { connection.killClient("127.0.0.1", 1001); - verifyNativeConnectionInvocation().clientKill(eq("127.0.0.1:1001")); + verify(jedisSpy).clientKill(eq("127.0.0.1:1001")); } @Test // DATAREDIS-270 public void getClientNameShouldSendRequestCorrectly() { connection.getClientName(); - verifyNativeConnectionInvocation().clientGetname(); + verify(jedisSpy).clientGetname(); } @Test // DATAREDIS-277 @@ -111,14 +111,14 @@ void replicaOfShouldThrowExectpionWhenCalledForNullHost() { public void replicaOfShouldBeSentCorrectly() { connection.replicaOf("127.0.0.1", 1001); - verifyNativeConnectionInvocation().slaveof(eq("127.0.0.1"), eq(1001)); + verify(jedisSpy).replicaof(eq("127.0.0.1"), eq(1001)); } @Test // DATAREDIS-277 public void replicaOfNoOneShouldBeSentCorrectly() { connection.replicaOfNoOne(); - verifyNativeConnectionInvocation().slaveofNoOne(); + verify(jedisSpy).replicaofNoOne(); } @Test // DATAREDIS-330 @@ -252,7 +252,7 @@ public void hScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException @Test // DATAREDIS-714 void doesNotSelectDbWhenCurrentDbMatchesDesiredOne() { - Jedis jedisSpy = spy(new MockedClientJedis("http://localhost:1234", getNativeRedisConnectionMock())); + Jedis jedisSpy = spy(new Jedis(getNativeRedisConnectionMock())); new JedisConnection(jedisSpy); verify(jedisSpy, never()).select(anyInt()); @@ -261,7 +261,7 @@ void doesNotSelectDbWhenCurrentDbMatchesDesiredOne() { @Test // DATAREDIS-714 void doesNotSelectDbWhenCurrentDbDoesNotMatchDesiredOne() { - Jedis jedisSpy = spy(new MockedClientJedis("http://localhost:1234", getNativeRedisConnectionMock())); + Jedis jedisSpy = spy(new Jedis(getNativeRedisConnectionMock())); when(jedisSpy.getDB()).thenReturn(3); new JedisConnection(jedisSpy); @@ -279,9 +279,24 @@ public void setUp() { connection.openPipeline(); } + @Test + @Disabled + @Override + void shutdownWithNullShouldDelegateCommandCorrectly() {} + + @Test + @Disabled + @Override + void shutdownNosaveShouldBeSentCorrectly() {} + + @Test + @Disabled + @Override + void shutdownSaveShouldBeSentCorrectly() {} + @Test // DATAREDIS-267 public void killClientShouldDelegateCallCorrectly() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.killClientShouldDelegateCallCorrectly()); } @@ -289,7 +304,7 @@ public void killClientShouldDelegateCallCorrectly() { @Override // DATAREDIS-270 public void getClientNameShouldSendRequestCorrectly() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.getClientNameShouldSendRequestCorrectly()); } @@ -297,74 +312,64 @@ public void getClientNameShouldSendRequestCorrectly() { @Override // DATAREDIS-277 public void replicaOfShouldBeSentCorrectly() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.replicaOfShouldBeSentCorrectly()); } @Test // DATAREDIS-277 public void replicaOfNoOneShouldBeSentCorrectly() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.replicaOfNoOneShouldBeSentCorrectly()); } @Test // DATAREDIS-531 public void scanShouldKeepTheConnectionOpen() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.scanShouldKeepTheConnectionOpen()); } @Test // DATAREDIS-531 public void scanShouldCloseTheConnectionWhenCursorIsClosed() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.scanShouldCloseTheConnectionWhenCursorIsClosed()); } @Test // DATAREDIS-531 public void sScanShouldKeepTheConnectionOpen() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.sScanShouldKeepTheConnectionOpen()); } @Test // DATAREDIS-531 public void sScanShouldCloseTheConnectionWhenCursorIsClosed() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.sScanShouldCloseTheConnectionWhenCursorIsClosed()); } @Test // DATAREDIS-531 public void zScanShouldKeepTheConnectionOpen() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.zScanShouldKeepTheConnectionOpen()); } @Test // DATAREDIS-531 public void zScanShouldCloseTheConnectionWhenCursorIsClosed() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.zScanShouldCloseTheConnectionWhenCursorIsClosed()); } @Test // DATAREDIS-531 public void hScanShouldKeepTheConnectionOpen() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.hScanShouldKeepTheConnectionOpen()); } @Test // DATAREDIS-531 public void hScanShouldCloseTheConnectionWhenCursorIsClosed() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> super.hScanShouldCloseTheConnectionWhenCursorIsClosed()); } } - /** - * {@link Jedis} extension allowing to use mocked object as {@link Client}. - */ - private static class MockedClientJedis extends Jedis { - - MockedClientJedis(String host, Client client) { - super(host); - ReflectionTestUtils.setField(this, "client", client); - } - } } 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 34ad2361fb..7bdd6b1b29 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 @@ -17,7 +17,6 @@ import static org.assertj.core.api.Assertions.*; -import org.junit.jupiter.api.Test; import redis.clients.jedis.params.GetExParams; import redis.clients.jedis.params.SetParams; @@ -29,6 +28,8 @@ import java.util.Map; import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + import org.springframework.data.redis.connection.RedisServer; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.RedisZSetCommands.Range; @@ -217,16 +218,14 @@ void toSetCommandExPxOptionShouldReturnEXforMilliseconds() { void convertsExpirationToSetPXAT() { assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS))) - .extracting(SetParams::toString) - .isEqualTo(SetParams.setParams().pxAt(10).toString()); + .extracting(SetParams::toString).isEqualTo(SetParams.setParams().pxAt(10).toString()); } @Test // GH-2050 void convertsExpirationToSetEXAT() { assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.unixTimestamp(1, TimeUnit.MINUTES))) - .extracting(SetParams::toString) - .isEqualTo(SetParams.setParams().exAt(60).toString()); + .extracting(SetParams::toString).isEqualTo(SetParams.setParams().exAt(60).toString()); } @Test // DATAREDIS-316, DATAREDIS-749 @@ -247,24 +246,21 @@ void toSetCommandNxXxOptionShouldReturnEmptyArrayforUpsert() { @Test // GH-2050 void convertsExpirationToGetExEX() { - assertThat(JedisConverters.toGetExParams(Expiration.seconds(10))) - .extracting(GetExParams::toString) + assertThat(JedisConverters.toGetExParams(Expiration.seconds(10))).extracting(GetExParams::toString) .isEqualTo(new GetExParams().ex(10).toString()); } @Test // GH-2050 void convertsExpirationWithTimeUnitToGetExEX() { - assertThat(JedisConverters.toGetExParams(Expiration.from(1, TimeUnit.MINUTES))) - .extracting(GetExParams::toString) + assertThat(JedisConverters.toGetExParams(Expiration.from(1, TimeUnit.MINUTES))).extracting(GetExParams::toString) .isEqualTo(new GetExParams().ex(60).toString()); } @Test // GH-2050 void convertsExpirationToGetExPEX() { - assertThat(JedisConverters.toGetExParams(Expiration.milliseconds(10))) - .extracting(GetExParams::toString) + assertThat(JedisConverters.toGetExParams(Expiration.milliseconds(10))).extracting(GetExParams::toString) .isEqualTo(new GetExParams().px(10).toString()); } @@ -272,24 +268,21 @@ void convertsExpirationToGetExPEX() { void convertsExpirationToGetExEXAT() { assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(10, TimeUnit.SECONDS))) - .extracting(GetExParams::toString) - .isEqualTo(new GetExParams().exAt(10).toString()); + .extracting(GetExParams::toString).isEqualTo(new GetExParams().exAt(10).toString()); } @Test // GH-2050 void convertsExpirationWithTimeUnitToGetExEXAT() { assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(1, TimeUnit.MINUTES))) - .extracting(GetExParams::toString) - .isEqualTo(new GetExParams().exAt(60).toString()); + .extracting(GetExParams::toString).isEqualTo(new GetExParams().exAt(60).toString()); } @Test // GH-2050 void convertsExpirationToGetExPXAT() { assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS))) - .extracting(GetExParams::toString) - .isEqualTo(new GetExParams().pxAt(10).toString()); + .extracting(GetExParams::toString).isEqualTo(new GetExParams().pxAt(10).toString()); } private void verifyRedisServerInfo(RedisServer server, Map values) { diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverterUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverterUnitTests.java index 5761031980..b57233de83 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverterUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisExceptionConverterUnitTests.java @@ -19,7 +19,7 @@ import redis.clients.jedis.HostAndPort; import redis.clients.jedis.exceptions.JedisAskDataException; -import redis.clients.jedis.exceptions.JedisClusterMaxAttemptsException; +import redis.clients.jedis.exceptions.JedisClusterOperationException; import redis.clients.jedis.exceptions.JedisMovedDataException; import org.junit.jupiter.api.Test; @@ -38,8 +38,8 @@ class JedisExceptionConverterUnitTests { @Test // DATAREDIS-315 void shouldConvertMovedDataException() { - DataAccessException converted = converter.convert(new JedisMovedDataException("MOVED 3999 127.0.0.1:6381", - new HostAndPort("127.0.0.1", 6381), 3999)); + DataAccessException converted = converter + .convert(new JedisMovedDataException("MOVED 3999 127.0.0.1:6381", new HostAndPort("127.0.0.1", 6381), 3999)); assertThat(converted).isInstanceOf(ClusterRedirectException.class); assertThat(((ClusterRedirectException) converted).getSlot()).isEqualTo(3999); @@ -50,8 +50,8 @@ void shouldConvertMovedDataException() { @Test // DATAREDIS-315 void shouldConvertAskDataException() { - DataAccessException converted = converter.convert(new JedisAskDataException("ASK 3999 127.0.0.1:6381", - new HostAndPort("127.0.0.1", 6381), 3999)); + DataAccessException converted = converter + .convert(new JedisAskDataException("ASK 3999 127.0.0.1:6381", new HostAndPort("127.0.0.1", 6381), 3999)); assertThat(converted).isInstanceOf(ClusterRedirectException.class); assertThat(((ClusterRedirectException) converted).getSlot()).isEqualTo(3999); @@ -63,7 +63,7 @@ void shouldConvertAskDataException() { void shouldConvertMaxRedirectException() { DataAccessException converted = converter - .convert(new JedisClusterMaxAttemptsException("Too many redirections?")); + .convert(new JedisClusterOperationException("No more cluster attempts left.")); assertThat(converted).isInstanceOf(TooManyClusterRedirectionsException.class); } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/TransactionalJedisIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/TransactionalJedisIntegrationTests.java index 8a318dbf76..a54707530e 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/TransactionalJedisIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/TransactionalJedisIntegrationTests.java @@ -34,11 +34,7 @@ public static class JedisContextConfiguration extends RedisContextConfiguration @Override @Bean public JedisConnectionFactory redisConnectionFactory() { - - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.setHostName(SettingsUtils.getHost()); - factory.setPort(SettingsUtils.getPort()); - return factory; + return new JedisConnectionFactory(SettingsUtils.standaloneConfiguration()); } } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java b/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java index e59479ceb5..0a4ce73e2c 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/extension/JedisConnectionFactoryExtension.java @@ -180,13 +180,11 @@ static class ManagedJedisConnectionFactory extends JedisConnectionFactory super(standaloneConfig, clientConfig); } - ManagedJedisConnectionFactory(RedisSentinelConfiguration sentinelConfig, - JedisClientConfiguration clientConfig) { + ManagedJedisConnectionFactory(RedisSentinelConfiguration sentinelConfig, JedisClientConfiguration clientConfig) { super(sentinelConfig, clientConfig); } - ManagedJedisConnectionFactory(RedisClusterConfiguration clusterConfig, - JedisClientConfiguration clientConfig) { + ManagedJedisConnectionFactory(RedisClusterConfiguration clusterConfig, JedisClientConfiguration clientConfig) { super(clusterConfig, clientConfig); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java index 476214a554..3a46192be3 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java @@ -43,6 +43,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Range.Bound; import org.springframework.data.geo.Circle; import org.springframework.data.geo.Distance; @@ -1402,7 +1403,7 @@ public void mSetShouldWorkWhenKeysMapToSameSlot() { @Test // DATAREDIS-315 public void moveShouldNotBeSupported() { - assertThatExceptionOfType(UnsupportedOperationException.class) + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class) .isThrownBy(() -> clusterConnection.move(KEY_1_BYTES, 3)); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java index f1c90e671a..7d906d1c1b 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.SettingsUtils; import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests; @@ -139,7 +140,7 @@ void testCloseNonPooledConnectionNotShared() { @Test public void testSelect() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> super.testSelect()); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(() -> super.testSelect()); } @Test diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java index 2cfbcb160a..1dfd484b92 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.AbstractConnectionPipelineIntegrationTests; import org.springframework.data.redis.connection.DefaultStringRedisConnection; import org.springframework.data.redis.connection.StringRedisConnection; @@ -43,7 +44,7 @@ public class LettuceConnectionPipelineIntegrationTests extends AbstractConnectio @Test public void testSelect() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> super.testSelect()); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(() -> super.testSelect()); } @Test @@ -69,11 +70,4 @@ public void testMove() { } } - @Test - @Override - // DATAREDIS-268 - public void testListClientsContainsAtLeastOneElement() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(() -> super.testListClientsContainsAtLeastOneElement()); - } } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxFlushOnEndIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxFlushOnEndIntegrationTests.java index 335b267728..61a8767bf1 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxFlushOnEndIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxFlushOnEndIntegrationTests.java @@ -24,6 +24,6 @@ * @author Mark Paluch */ @ContextConfiguration("LettuceConnectionPipelineFlushOnEndIntegrationTests-context.xml") -public class LettuceConnectionPipelineTxFlushOnEndIntegrationTests extends LettuceConnectionPipelineTxIntegrationTests { +class LettuceConnectionPipelineTxFlushOnEndIntegrationTests extends LettuceConnectionPipelineTxIntegrationTests { } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java index 692761849c..17a955ce52 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java @@ -28,7 +28,7 @@ * @author Jennifer Hickey * @author Christoph Strobl */ -public class LettuceConnectionPipelineTxIntegrationTests extends LettuceConnectionTransactionIntegrationTests { +class LettuceConnectionPipelineTxIntegrationTests extends LettuceConnectionTransactionIntegrationTests { @Test @Disabled("Different exception") @@ -76,12 +76,4 @@ protected List getResults() { return txResults; } - @Test - @Override - // DATAREDIS-268 - public void testListClientsContainsAtLeastOneElement() { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(super::testListClientsContainsAtLeastOneElement); - } - } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java index f776220145..147f2184ce 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.AbstractConnectionTransactionIntegrationTests; import org.springframework.data.redis.connection.DefaultStringRedisConnection; import org.springframework.data.redis.connection.StringRedisConnection; @@ -68,6 +69,6 @@ public void testMove() { @Test public void testSelect() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(super::testSelect); + assertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(super::testSelect); } } diff --git a/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java index 916761bc7f..be75f8c536 100644 --- a/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/RedisTemplateIntegrationTests.java @@ -343,6 +343,9 @@ public void testExecutePipelinedNonNullRedisCallback() { @SuppressWarnings({ "rawtypes", "unchecked" }) @ParameterizedRedisTest public void testExecutePipelinedTx() { + + assumeThat(redisTemplate.getConnectionFactory()).isInstanceOf(LettuceConnectionFactory.class); + K key1 = keyFactory.instance(); V value1 = valueFactory.instance(); List pipelinedResults = redisTemplate.executePipelined(new SessionCallback() { @@ -370,6 +373,7 @@ public Object execute(RedisOperations operations) throws DataAccessException { @SuppressWarnings({ "rawtypes", "unchecked" }) @ParameterizedRedisTest void testExecutePipelinedTxCustomSerializer() { + assumeThat(redisTemplate.getConnectionFactory()).isInstanceOf(LettuceConnectionFactory.class); assumeThat(redisTemplate instanceof StringRedisTemplate).isTrue(); List pipelinedResults = redisTemplate.executePipelined(new SessionCallback() { public Object execute(RedisOperations operations) throws DataAccessException { @@ -580,9 +584,6 @@ void testGetExpireDuration() { @SuppressWarnings({ "unchecked", "rawtypes" }) public void testGetExpireMillisUsingTransactions() { - assumeThat(redisTemplate.getConnectionFactory() instanceof JedisConnectionFactory - || redisTemplate.getConnectionFactory() instanceof LettuceConnectionFactory).isTrue(); - K key = keyFactory.instance(); List result = redisTemplate.execute(new SessionCallback>() { @@ -607,9 +608,6 @@ public List execute(RedisOperations operations) throws DataAccessExcepti @SuppressWarnings({ "unchecked", "rawtypes" }) public void testGetExpireMillisUsingPipelining() { - assumeThat(redisTemplate.getConnectionFactory() instanceof JedisConnectionFactory - || redisTemplate.getConnectionFactory() instanceof LettuceConnectionFactory).isTrue(); - K key = keyFactory.instance(); List result = redisTemplate.executePipelined(new SessionCallback() { diff --git a/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java b/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java index ee8b17fbff..8827520503 100644 --- a/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java +++ b/src/test/java/org/springframework/data/redis/test/extension/ShutdownQueue.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.test.extension; +import redis.clients.jedis.util.IOUtils; + import java.io.Closeable; import java.util.LinkedList; @@ -52,4 +54,8 @@ public void run() { public static void register(Closeable closeable) { INSTANCE.closeables.add(closeable); } + + public static void register(AutoCloseable closeable) { + INSTANCE.closeables.add(() -> IOUtils.closeQuietly(closeable)); + } }