From ce3b16c77a7536897b8da89e446d948ed82cde5c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 22 Feb 2022 14:20:08 +0100 Subject: [PATCH 01/12] Prepare issue branch. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 94effee5e3..7d4b52f3ab 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-2195-SNAPSHOT Spring Data Redis From 381585378c6b927656cbf5406b4a1aa289b40fd4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 22 Feb 2022 14:49:58 +0100 Subject: [PATCH 02/12] Remove slaveOf methods in favor of renamed replicaOf methods/commands. The API exposes now the renamed command terminology and no longer the deprecated one. Closes #2195 --- .../appendix/appendix-command-reference.adoc | 1 + .../redis/connection/ClusterTopology.java | 6 ++-- .../DefaultStringRedisConnection.java | 8 ++--- .../connection/DefaultedRedisConnection.java | 8 ++--- .../connection/ReactiveClusterCommands.java | 14 ++++---- .../connection/RedisClusterCommands.java | 14 ++++---- .../redis/connection/RedisClusterNode.java | 7 +--- .../redis/connection/RedisConfiguration.java | 3 +- .../data/redis/connection/RedisNode.java | 23 ++----------- .../connection/RedisSentinelCommands.java | 4 +-- .../data/redis/connection/RedisServer.java | 4 --- .../redis/connection/RedisServerCommands.java | 10 +++--- ...RedisStaticMasterReplicaConfiguration.java | 3 +- .../redis/connection/convert/Converters.java | 4 +-- .../jedis/JedisClusterConnection.java | 4 +-- .../jedis/JedisClusterServerCommands.java | 8 ++--- .../jedis/JedisSentinelConnection.java | 14 ++++---- .../connection/jedis/JedisServerCommands.java | 10 +++--- .../lettuce/LettuceClientConfiguration.java | 5 +-- .../lettuce/LettuceClusterConnection.java | 7 ++-- .../lettuce/LettuceClusterServerCommands.java | 8 ++--- .../connection/lettuce/LettuceConverters.java | 9 +++--- ...LettuceReactiveRedisClusterConnection.java | 4 +-- .../lettuce/LettuceSentinelConnection.java | 8 ++--- .../lettuce/LettuceServerCommands.java | 6 ++-- .../data/redis/core/ClusterOperations.java | 2 +- .../redis/core/DefaultClusterOperations.java | 4 +-- .../data/redis/core/RedisCommand.java | 1 + .../data/redis/core/RedisOperations.java | 8 ++--- .../data/redis/core/RedisTemplate.java | 10 +++--- .../connection/ClusterConnectionTests.java | 4 +-- .../connection/ClusterTestVariables.java | 9 +++--- .../connection/RedisConnectionUnitTests.java | 8 ++--- .../convert/ConvertersUnitTests.java | 8 ++--- .../jedis/JedisClusterConnectionTests.java | 32 +++++++++---------- .../JedisClusterConnectionUnitTests.java | 4 +-- .../jedis/JedisConnectionUnitTests.java | 20 ++++++------ .../JedisSentinelConnectionUnitTests.java | 24 +++++++------- .../jedis/JedisSentinelIntegrationTests.java | 10 +++--- .../LettuceClusterConnectionTests.java | 29 +++++++++-------- .../LettuceConnectionFactoryTests.java | 2 +- .../lettuce/LettuceConnectionUnitTests.java | 20 ++++++------ ...activeClusterCommandsIntegrationTests.java | 8 ++--- .../LettuceSentinelConnectionUnitTests.java | 16 +++++----- .../LettuceSentinelIntegrationTests.java | 16 +++++----- .../DefaultClusterOperationsUnitTests.java | 10 +++--- .../redis/core/RedisTemplateUnitTests.java | 12 +++---- 47 files changed, 210 insertions(+), 239 deletions(-) diff --git a/src/main/asciidoc/appendix/appendix-command-reference.adoc b/src/main/asciidoc/appendix/appendix-command-reference.adoc index 0b571a3b04..256a080ef0 100644 --- a/src/main/asciidoc/appendix/appendix-command-reference.adoc +++ b/src/main/asciidoc/appendix/appendix-command-reference.adoc @@ -115,6 +115,7 @@ |RANDOMKEY |X |RENAME |X |RENAMENX |X +|REPLICAOF |X |RESTORE |X |ROLE |- |RPOP |X diff --git a/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java b/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java index 1a9a57fe18..ac5b218d31 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java @@ -55,8 +55,8 @@ public Set getNodes() { } /** - * Get all nodes (master and slave) in cluster where {@code link-state} is {@literal connected} and {@code flags} does - * not contain {@literal fail} or {@literal fail?}. + * Get all nodes (master and replica) in cluster where {@code link-state} is {@literal connected} and {@code flags} + * does not contain {@literal fail} or {@literal fail?}. * * @return never {@literal null}. */ @@ -105,7 +105,7 @@ public Set getMasterNodes() { } /** - * Get the {@link RedisClusterNode}s (master and slave) serving s specific slot. + * Get the {@link RedisClusterNode}s (master and replica) serving s specific slot. * * @param slot * @return never {@literal null}. diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index b9afb28f5d..0892dace34 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -2433,13 +2433,13 @@ public List getClientList() { } @Override - public void slaveOf(String host, int port) { - this.delegate.slaveOf(host, port); + public void replicaOf(String host, int port) { + this.delegate.replicaOf(host, port); } @Override - public void slaveOfNoOne() { - this.delegate.slaveOfNoOne(); + public void replicaOfNoOne() { + this.delegate.replicaOfNoOne(); } @Override diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java index 624298bdb3..2f846fc508 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -1740,15 +1740,15 @@ default List getClientList() { /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ @Override @Deprecated - default void slaveOf(String host, int port) { - serverCommands().slaveOf(host, port); + default void replicaOf(String host, int port) { + serverCommands().replicaOf(host, port); } /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ @Override @Deprecated - default void slaveOfNoOne() { - serverCommands().slaveOfNoOne(); + default void replicaOfNoOne() { + serverCommands().replicaOfNoOne(); } /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveClusterCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveClusterCommands.java index 195b806932..86f91e0850 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveClusterCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveClusterCommands.java @@ -46,22 +46,22 @@ public interface ReactiveClusterCommands { Flux clusterGetNodes(); /** - * Retrieve information about connected slaves for given master node. + * Retrieve information about connected replicas for given master node. * * @param master must not be {@literal null}. * @return a {@link Flux} emitting {@link RedisClusterNode cluster nodes}, an {@link Flux#empty() empty one} if none * found. - * @see Redis Documentation: CLUSTER SLAVES + * @see Redis Documentation: CLUSTER REPLICAS */ - Flux clusterGetSlaves(RedisClusterNode master); + Flux clusterGetReplicas(RedisClusterNode master); /** - * Retrieve information about masters and their connected slaves. + * Retrieve information about masters and their connected replicas. * * @return never {@literal null}. - * @see Redis Documentation: CLUSTER SLAVES + * @see Redis Documentation: CLUSTER REPLICAS */ - Mono>> clusterGetMasterSlaveMap(); + Mono>> clusterGetMasterReplicaMap(); /** * Find the slot for a given {@code key}. @@ -184,7 +184,7 @@ public interface ReactiveClusterCommands { Flux clusterGetKeysInSlot(int slot, int count); /** - * Assign a {@literal slave} to given {@literal master}. + * Assign a {@literal replica} to given {@literal master}. * * @param master must not be {@literal null}. * @param replica must not be {@literal null}. diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java index a0eec7847e..f9e922079d 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java @@ -41,21 +41,21 @@ public interface RedisClusterCommands { Iterable clusterGetNodes(); /** - * Retrieve information about connected slaves for given master node. + * Retrieve information about connected replicas for given master node. * * @param master must not be {@literal null}. * @return never {@literal null}. - * @see Redis Documentation: CLUSTER SLAVES + * @see Redis Documentation: CLUSTER REPLICAS */ - Collection clusterGetSlaves(RedisClusterNode master); + Collection clusterGetReplicas(RedisClusterNode master); /** - * Retrieve information about masters and their connected slaves. + * Retrieve information about masters and their connected replicas. * * @return never {@literal null}. - * @see Redis Documentation: CLUSTER SLAVES + * @see Redis Documentation: CLUSTER REPLICAS */ - Map> clusterGetMasterSlaveMap(); + Map> clusterGetMasterReplicaMap(); /** * Find the slot for a given {@code key}. @@ -171,7 +171,7 @@ public interface RedisClusterCommands { List clusterGetKeysInSlot(int slot, Integer count); /** - * Assign a {@literal slave} to given {@literal master}. + * Assign a {@literal replica} to given {@literal master}. * * @param master must not be {@literal null}. * @param replica must not be {@literal null}. diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java index 9c4f25baac..48d707f2b5 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java @@ -242,7 +242,7 @@ public enum LinkState { */ public static enum Flag { - MYSELF("myself"), MASTER("master"), SLAVE("slave"), FAIL("fail"), PFAIL("fail?"), HANDSHAKE("handshake"), NOADDR( + MYSELF("myself"), MASTER("master"), REPLICA("slave"), FAIL("fail"), PFAIL("fail?"), HANDSHAKE("handshake"), NOADDR( "noaddr"), NOFLAGS("noflags"); private String raw; @@ -297,11 +297,6 @@ public RedisClusterNodeBuilder promotedAs(NodeType nodeType) { return this; } - public RedisClusterNodeBuilder slaveOf(String masterId) { - super.slaveOf(masterId); - return this; - } - @Override public RedisClusterNodeBuilder replicaOf(String masterId) { super.replicaOf(masterId); diff --git a/src/main/java/org/springframework/data/redis/connection/RedisConfiguration.java b/src/main/java/org/springframework/data/redis/connection/RedisConfiguration.java index 54d508b02e..2241500ca2 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisConfiguration.java @@ -482,8 +482,7 @@ interface ClusterConfiguration extends WithPassword { } /** - * Configuration interface suitable for Redis master/slave environments with fixed hosts.
- * Redis is undergoing a nomenclature change where the term replica is used synonymously to slave. + * Configuration interface suitable for Redis master/replica environments with fixed hosts. * * @author Christoph Strobl * @author Mark Paluch diff --git a/src/main/java/org/springframework/data/redis/connection/RedisNode.java b/src/main/java/org/springframework/data/redis/connection/RedisNode.java index b013545c5b..59025523c1 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisNode.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisNode.java @@ -142,20 +142,12 @@ public boolean isMaster() { return ObjectUtils.nullSafeEquals(NodeType.MASTER, getType()); } - /** - * @return - * @since 1.7 - */ - public boolean isSlave() { - return isReplica(); - } - /** * @return * @since 2.1 */ public boolean isReplica() { - return ObjectUtils.nullSafeEquals(NodeType.SLAVE, getType()); + return ObjectUtils.nullSafeEquals(NodeType.REPLICA, getType()); } /** @@ -214,7 +206,7 @@ public boolean equals(Object obj) { * @since 1.7 */ public enum NodeType { - MASTER, SLAVE + MASTER, REPLICA } /** @@ -279,17 +271,6 @@ public RedisNodeBuilder promotedAs(NodeType type) { return this; } - /** - * Set the id of the master node. - * - * @param masterId - * @return - * @since 1.7 - */ - public RedisNodeBuilder slaveOf(String masterId) { - return replicaOf(masterId); - } - /** * Set the id of the master node. * diff --git a/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java index 784dfc994c..49f0b14c01 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java @@ -42,12 +42,12 @@ public interface RedisSentinelCommands { Collection masters(); /** - * Show list of slaves for given {@literal master}. + * Show list of replicas for given {@literal master}. * * @param master must not be {@literal null}. * @return Collection of {@link RedisServer}s. Never {@literal null}. */ - Collection slaves(NamedNode master); + Collection replicas(NamedNode master); /** * Removes given {@literal master}. The server will no longer be monitored and will no longer be returned by diff --git a/src/main/java/org/springframework/data/redis/connection/RedisServer.java b/src/main/java/org/springframework/data/redis/connection/RedisServer.java index ea2d4d504c..e652a8b92e 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisServer.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisServer.java @@ -165,10 +165,6 @@ public Long getConfigEpoch() { return getLongValueOf(INFO.CONFIG_EPOCH); } - public Long getNumberSlaves() { - return getNumberReplicas(); - } - /** * Get the number of connected replicas. * diff --git a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java index ea7f7fb3d7..25fff02b4e 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java @@ -248,18 +248,18 @@ default Long time() { * * @param host must not be {@literal null}. * @param port - * @since 1.3 - * @see Redis Documentation: SLAVEOF + * @since 3.0 + * @see Redis Documentation: REPLICAOF */ - void slaveOf(String host, int port); + void replicaOf(String host, int port); /** * Change server into master. * * @since 1.3 - * @see Redis Documentation: SLAVEOF + * @see Redis Documentation: REPLICAOF */ - void slaveOfNoOne(); + void replicaOfNoOne(); /** * Atomically transfer a key from a source Redis instance to a destination Redis instance. On success the key is diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStaticMasterReplicaConfiguration.java b/src/main/java/org/springframework/data/redis/connection/RedisStaticMasterReplicaConfiguration.java index f69138b7f7..840a1c98e5 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStaticMasterReplicaConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStaticMasterReplicaConfiguration.java @@ -28,8 +28,7 @@ * Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} using the provided * Master / Replica configuration to nodes know to not change address. Eg. when connecting to * AWS ElastiCache with Read Replicas.
- * Note: Redis is undergoing a nomenclature change where the term replica is used synonymously to slave. Please also - * note that a Master/Replica connection cannot be used for Pub/Sub operations. + * Please also note that a Master/Replica connection cannot be used for Pub/Sub operations. * * @author Mark Paluch * @author Christoph Strobl 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 37145d6574..d3a9f27d7c 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 @@ -570,13 +570,13 @@ public RedisClusterNode convert(String source) { RedisClusterNodeBuilder nodeBuilder = RedisClusterNode.newRedisClusterNode() .listeningAt(hostAndPort[0], Integer.valueOf(portPart)) // .withId(args[ID_INDEX]) // - .promotedAs(flags.contains(Flag.MASTER) ? NodeType.MASTER : NodeType.SLAVE) // + .promotedAs(flags.contains(Flag.MASTER) ? NodeType.MASTER : NodeType.REPLICA) // .serving(range) // .withFlags(flags) // .linkState(parseLinkState(args)); if (!args[MASTER_ID_INDEX].isEmpty() && !args[MASTER_ID_INDEX].startsWith("-")) { - nodeBuilder.slaveOf(args[MASTER_ID_INDEX]); + nodeBuilder.replicaOf(args[MASTER_ID_INDEX]); } return nodeBuilder.build(); 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 424cf4cb1a..a8037fee9e 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 @@ -562,7 +562,7 @@ public Set clusterGetNodes() { } @Override - public Set clusterGetSlaves(RedisClusterNode master) { + public Set clusterGetReplicas(RedisClusterNode master) { Assert.notNull(master, "Master cannot be null!"); @@ -575,7 +575,7 @@ public Set clusterGetSlaves(RedisClusterNode master) { } @Override - public Map> clusterGetMasterSlaveMap() { + public Map> clusterGetMasterReplicaMap() { List>> nodeResults = clusterCommandExecutor .executeCommandAsyncOnNodes((JedisClusterCommandCallback>) client -> { 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 047cb29e73..a796450f52 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 @@ -350,15 +350,15 @@ public List getClientList(RedisClusterNode node) { } @Override - public void slaveOf(String host, int port) { + public void replicaOf(String host, int port) { throw new InvalidDataAccessApiUsageException( - "SlaveOf is not supported in cluster environment. Please use CLUSTER REPLICATE."); + "REPLICAOF is not supported in cluster environment. Please use CLUSTER REPLICATE."); } @Override - public void slaveOfNoOne() { + public void replicaOfNoOne() { throw new InvalidDataAccessApiUsageException( - "SlaveOf is not supported in cluster environment. Please use CLUSTER REPLICATE."); + "REPLICAOF is not supported in cluster environment. Please use CLUSTER REPLICATE."); } @Override diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnection.java index 6d96771433..d6e0e70220 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnection.java @@ -64,21 +64,21 @@ public List masters() { } @Override - public List slaves(NamedNode master) { + public List replicas(NamedNode master) { - Assert.notNull(master, "Master node cannot be 'null' when loading slaves."); - return slaves(master.getName()); + Assert.notNull(master, "Master node cannot be 'null' when loading replicas."); + return replicas(master.getName()); } /** * @param masterName - * @see RedisSentinelCommands#slaves(NamedNode) + * @see RedisSentinelCommands#replicas(NamedNode) * @return */ - public List slaves(String masterName) { + public List replicas(String masterName) { - Assert.hasText(masterName, "Name of redis master cannot be 'null' or empty when loading slaves."); - return JedisConverters.toListOfRedisServer(jedis.sentinelSlaves(masterName)); + Assert.hasText(masterName, "Name of redis master cannot be 'null' or empty when loading replicas."); + return JedisConverters.toListOfRedisServer(jedis.sentinelReplicas(masterName)); } @Override 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 5a2f5287ba..54e1865af7 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 @@ -194,22 +194,22 @@ public List getClientList() { } @Override - public void slaveOf(String host, int port) { + public void replicaOf(String host, int port) { - Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); + Assert.hasText(host, "Host must not be null for 'REPLICAOF' command."); if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode."); + throw new UnsupportedOperationException("'REPLICAOF' cannot be called in pipeline / transaction mode."); } connection.invokeStatus().just(it -> it.slaveof(host, port)); } @Override - public void slaveOfNoOne() { + public void replicaOfNoOne() { if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode."); + throw new UnsupportedOperationException("'REPLICAOF' cannot be called in pipeline / transaction mode."); } connection.invokeStatus().just(BinaryJedis::slaveofNoOne); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java index 40089d81f4..09b5fa38c6 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java @@ -89,8 +89,6 @@ public interface LettuceClientConfiguration { Optional getClientName(); /** - * Note: Redis is undergoing a nomenclature change where the term replica is used synonymously to slave. - * * @return the optional {@link io.lettuce.core.ReadFrom} setting. * @since 2.1 */ @@ -240,8 +238,7 @@ public LettuceClientConfigurationBuilder clientOptions(ClientOptions clientOptio } /** - * Configure {@link ReadFrom}. Enables Master/Replica operations if configured.
- * Note: Redis is undergoing a nomenclature change where the term replica is used synonymously to slave. + * Configure {@link ReadFrom}. Enables Master/Replica operations if configured. * * @param readFrom must not be {@literal null}. * @return {@literal this} builder. diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index 1927177990..b4b4ffd71d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -15,7 +15,6 @@ */ package org.springframework.data.redis.connection.lettuce; -import io.lettuce.core.RedisException; import io.lettuce.core.RedisURI; import io.lettuce.core.api.sync.BaseRedisCommands; import io.lettuce.core.cluster.RedisClusterClient; @@ -33,9 +32,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.DisposableBean; import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; @@ -275,7 +274,7 @@ public List clusterGetNodes() { } @Override - public Set clusterGetSlaves(RedisClusterNode master) { + public Set clusterGetReplicas(RedisClusterNode master) { Assert.notNull(master, "Master must not be null!"); @@ -288,7 +287,7 @@ public Set clusterGetSlaves(RedisClusterNode master) { } @Override - public Map> clusterGetMasterSlaveMap() { + public Map> clusterGetMasterReplicaMap() { List>> nodeResults = clusterCommandExecutor.executeCommandAsyncOnNodes( (LettuceClusterCommandCallback>) client -> Converters diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java index 17aa4d302a..5e2b4bcb8d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterServerCommands.java @@ -258,15 +258,15 @@ public List getClientList(RedisClusterNode node) { } @Override - public void slaveOf(String host, int port) { + public void replicaOf(String host, int port) { throw new InvalidDataAccessApiUsageException( - "SlaveOf is not supported in cluster environment. Please use CLUSTER REPLICATE."); + "REPLICAOF is not supported in cluster environment. Please use CLUSTER REPLICATE."); } @Override - public void slaveOfNoOne() { + public void replicaOfNoOne() { throw new InvalidDataAccessApiUsageException( - "SlaveOf is not supported in cluster environment. Please use CLUSTER REPLICATE."); + "REPLICAOF is not supported in cluster environment. Please use CLUSTER REPLICATE."); } private NodeResult executeCommandOnSingleNode(LettuceClusterCommandCallback command, diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index f54c3f3a04..72b36d612c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -478,7 +478,7 @@ private static Converter flags = parseFlags(source.getFlags()); return RedisClusterNode.newRedisClusterNode().listeningAt(source.getUri().getHost(), source.getUri().getPort()) - .withId(source.getNodeId()).promotedAs(flags.contains(Flag.MASTER) ? NodeType.MASTER : NodeType.SLAVE) + .withId(source.getNodeId()).promotedAs(flags.contains(Flag.MASTER) ? NodeType.MASTER : NodeType.REPLICA) .serving(new SlotRange(source.getSlots())).withFlags(flags) - .linkState(source.isConnected() ? LinkState.CONNECTED : LinkState.DISCONNECTED).slaveOf(source.getSlaveOf()) + .linkState(source.isConnected() ? LinkState.CONNECTED : LinkState.DISCONNECTED).replicaOf(source.getSlaveOf()) .build(); } @@ -757,7 +757,8 @@ private static Set parseFlags(@Nullable Set source) { flags.add(Flag.NOADDR); break; case SLAVE: - flags.add(Flag.SLAVE); + case REPLICA: + flags.add(Flag.REPLICA); break; } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisClusterConnection.java index ef4b2069b6..55a5532a00 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisClusterConnection.java @@ -168,7 +168,7 @@ public Flux clusterGetNodes() { } @Override - public Flux clusterGetSlaves(RedisClusterNode master) { + public Flux clusterGetReplicas(RedisClusterNode master) { Assert.notNull(master, "Master must not be null!"); @@ -178,7 +178,7 @@ public Flux clusterGetSlaves(RedisClusterNode master) { } @Override - public Mono>> clusterGetMasterSlaveMap() { + public Mono>> clusterGetMasterReplicaMap() { return Flux.fromStream(() -> topologyProvider.getTopology().getActiveMasterNodes().stream()) // .flatMap(node -> { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java index 3833ab2485..39a534ad89 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java @@ -164,20 +164,20 @@ public List masters() { } @Override - public List slaves(NamedNode master) { + public List replicas(NamedNode master) { - Assert.notNull(master, "Master node cannot be 'null' when loading slaves."); + Assert.notNull(master, "Master node cannot be 'null' when loading replicas."); return slaves(master.getName()); } /** * @param masterName - * @see org.springframework.data.redis.connection.RedisSentinelCommands#slaves(org.springframework.data.redis.connection.NamedNode) + * @see org.springframework.data.redis.connection.RedisSentinelCommands#replicas(org.springframework.data.redis.connection.NamedNode) * @return */ public List slaves(String masterName) { - Assert.hasText(masterName, "Name of redis master cannot be 'null' or empty when loading slaves."); + Assert.hasText(masterName, "Name of redis master cannot be 'null' or empty when loading replicas."); try { return LettuceConverters.toListOfRedisServer(getSentinelCommands().slaves(masterName)); } catch (Exception e) { 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 6605786833..0f4f8020ea 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 @@ -191,15 +191,15 @@ public List getClientList() { } @Override - public void slaveOf(String host, int port) { + public void replicaOf(String host, int port) { - Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); + Assert.hasText(host, "Host must not be null for 'REPLICAOF' command."); connection.invoke().just(RedisServerAsyncCommands::slaveof, host, port); } @Override - public void slaveOfNoOne() { + public void replicaOfNoOne() { connection.invoke().just(RedisServerAsyncCommands::slaveofNoOne); } diff --git a/src/main/java/org/springframework/data/redis/core/ClusterOperations.java b/src/main/java/org/springframework/data/redis/core/ClusterOperations.java index 620103da95..f7a7c8b395 100644 --- a/src/main/java/org/springframework/data/redis/core/ClusterOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ClusterOperations.java @@ -121,7 +121,7 @@ public interface ClusterOperations { * @param node must not be {@literal null}. * @return */ - Collection getSlaves(RedisClusterNode node); + Collection getReplicas(RedisClusterNode node); /** * Synchronous save current db snapshot on server. diff --git a/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java index cef665943f..0d4080ff65 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java @@ -150,11 +150,11 @@ public void flushDb(final RedisClusterNode node) { } @Override - public Collection getSlaves(final RedisClusterNode node) { + public Collection getReplicas(final RedisClusterNode node) { Assert.notNull(node, "ClusterNode must not be null."); - return doInCluster(connection -> connection.clusterGetSlaves(node)); + return doInCluster(connection -> connection.clusterGetReplicas(node)); } @Override diff --git a/src/main/java/org/springframework/data/redis/core/RedisCommand.java b/src/main/java/org/springframework/data/redis/core/RedisCommand.java index 1fec800aec..fb69f2c6e4 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisCommand.java +++ b/src/main/java/org/springframework/data/redis/core/RedisCommand.java @@ -145,6 +145,7 @@ public enum RedisCommand { RANAME("w", 2, 2), // RENAME("w", 2, 2), // RENAMENX("w", 2, 2), // + REPLICAOF("w", 2), // RESTORE("w", 3, 3), // RPOP("rw", 1, 1), // RPOPLPUSH("rw", 2, 2), // diff --git a/src/main/java/org/springframework/data/redis/core/RedisOperations.java b/src/main/java/org/springframework/data/redis/core/RedisOperations.java index 20505059fc..2d204b63da 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -576,17 +576,17 @@ default void restore(K key, byte[] value, long timeToLive, TimeUnit unit) { * @param host must not be {@literal null}. * @param port * @since 1.3 - * @see Redis Documentation: SLAVEOF + * @see Redis Documentation: REPLICAOF */ - void slaveOf(String host, int port); + void replicaOf(String host, int port); /** * Change server into master. * * @since 1.3 - * @see Redis Documentation: SLAVEOF + * @see Redis Documentation: REPLICAOF */ - void slaveOfNoOne(); + void replicaOfNoOne(); /** * Publishes the given message to the given channel. diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 6c3951057d..dc35f5eec0 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -1023,23 +1023,23 @@ public List getClientList() { } /* - * @see org.springframework.data.redis.core.RedisOperations#slaveOf(java.lang.String, int) + * @see org.springframework.data.redis.core.RedisOperations#replicaOf(java.lang.String, int) */ @Override - public void slaveOf(final String host, final int port) { + public void replicaOf(final String host, final int port) { execute((RedisCallback) connection -> { - connection.slaveOf(host, port); + connection.replicaOf(host, port); return null; }); } @Override - public void slaveOfNoOne() { + public void replicaOfNoOne() { execute((RedisCallback) connection -> { - connection.slaveOfNoOne(); + connection.replicaOfNoOne(); return null; }); } diff --git a/src/test/java/org/springframework/data/redis/connection/ClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/ClusterConnectionTests.java index cd2488e344..8cabca3121 100644 --- a/src/test/java/org/springframework/data/redis/connection/ClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/ClusterConnectionTests.java @@ -61,10 +61,10 @@ public interface ClusterConnectionTests { void clientListShouldGetInfosForAllClients(); // DATAREDIS-315 - void clusterGetMasterSlaveMapShouldListMastersAndSlavesCorrectly(); + void clusterGetMasterReplicaMapShouldListMastersAndReplicasCorrectly(); // DATAREDIS-315 - void clusterGetSlavesShouldReturnSlaveCorrectly(); + void clusterGetReplicasShouldReturnReplicaCorrectly(); // DATAREDIS-315 void countKeysShouldReturnNumberOfKeysInSlot(); diff --git a/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java b/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java index 22dc029903..1ec0c75729 100644 --- a/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java +++ b/src/test/java/org/springframework/data/redis/connection/ClusterTestVariables.java @@ -38,12 +38,12 @@ public abstract class ClusterTestVariables { public static final int MASTER_NODE_1_PORT = 7379; public static final int MASTER_NODE_2_PORT = 7380; public static final int MASTER_NODE_3_PORT = 7381; - public static final int SLAVEOF_NODE_1_PORT = 7382; + public static final int REPLICAOF_NODE_1_PORT = 7382; public static final String MASTER_NODE_1_ID = "ef570f86c7b1a953846668debc177a3a16733420"; public static final String MASTER_NODE_2_ID = "0f2ee5df45d18c50aca07228cc18b1da96fd5e84"; public static final String MASTER_NODE_3_ID = "3b9b8192a874fa8f1f09dbc0ee20afab5738eee7"; - public static final String SLAVEOF_NODE_1_ID = "b8b5ee73b1d1997abff694b3fe8b2397d2138b6d"; + public static final String REPLICAOF_NODE_1_ID = "b8b5ee73b1d1997abff694b3fe8b2397d2138b6d"; public static final RedisClusterNode CLUSTER_NODE_1 = RedisClusterNode.newRedisClusterNode() .listeningAt(CLUSTER_HOST, MASTER_NODE_1_PORT).withId(MASTER_NODE_1_ID).promotedAs(NodeType.MASTER).build(); @@ -51,8 +51,9 @@ public abstract class ClusterTestVariables { .listeningAt(CLUSTER_HOST, MASTER_NODE_2_PORT).withId(MASTER_NODE_2_ID).promotedAs(NodeType.MASTER).build(); public static final RedisClusterNode CLUSTER_NODE_3 = RedisClusterNode.newRedisClusterNode() .listeningAt(CLUSTER_HOST, MASTER_NODE_3_PORT).withId(MASTER_NODE_3_ID).promotedAs(NodeType.MASTER).build(); - public static final RedisClusterNode SLAVE_OF_NODE_1 = RedisClusterNode.newRedisClusterNode() - .listeningAt(CLUSTER_HOST, SLAVEOF_NODE_1_PORT).withId(SLAVEOF_NODE_1_ID).promotedAs(NodeType.SLAVE).build(); + public static final RedisClusterNode REPLICA_OF_NODE_1 = RedisClusterNode.newRedisClusterNode() + .listeningAt(CLUSTER_HOST, REPLICAOF_NODE_1_PORT).withId(REPLICAOF_NODE_1_ID).promotedAs(NodeType.REPLICA) + .build(); public static final RedisClusterNode UNKNOWN_CLUSTER_NODE = new RedisClusterNode("8.8.8.8", 6379); diff --git a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java index 55b0cb8709..31de230460 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java @@ -769,8 +769,8 @@ public Boolean getBit(byte[] key, long offset) { return delegate.getBit(key, offset); } - public void slaveOf(String host, int port) { - delegate.slaveOf(host, port); + public void replicaOf(String host, int port) { + delegate.replicaOf(host, port); } public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { @@ -789,8 +789,8 @@ public Boolean setBit(byte[] key, long offset, boolean value) { return delegate.setBit(key, offset, value); } - public void slaveOfNoOne() { - delegate.slaveOfNoOne(); + public void replicaOfNoOne() { + delegate.replicaOfNoOne(); } public void restore(byte[] key, long ttlInMillis, byte[] serializedValue, boolean replace) { diff --git a/src/test/java/org/springframework/data/redis/connection/convert/ConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/convert/ConvertersUnitTests.java index 43bbdc66e6..61c09106f4 100644 --- a/src/test/java/org/springframework/data/redis/connection/convert/ConvertersUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/convert/ConvertersUnitTests.java @@ -103,10 +103,10 @@ void toSetOfRedis30ClusterNodesShouldConvertSingleStringNodesResponseCorrectly() assertThat(node.getId()).isEqualTo("8cad73f63eb996fedba89f041636f17d88cda075"); assertThat(node.getHost()).isEqualTo("127.0.0.1"); assertThat(node.getPort()).isEqualTo(7369); - assertThat(node.getType()).isEqualTo(NodeType.SLAVE); + assertThat(node.getType()).isEqualTo(NodeType.REPLICA); assertThat(node.getMasterId()).isEqualTo("ef570f86c7b1a953846668debc177a3a16733420"); assertThat(node.getSlotRange()).isNotNull(); - assertThat(node.getFlags()).contains(Flag.SLAVE); + assertThat(node.getFlags()).contains(Flag.REPLICA); assertThat(node.getLinkState()).isEqualTo(LinkState.CONNECTED); } @@ -153,10 +153,10 @@ void toSetOfRedis32ClusterNodesShouldConvertSingleStringNodesResponseCorrectly() assertThat(node.getId()).isEqualTo("8cad73f63eb996fedba89f041636f17d88cda075"); assertThat(node.getHost()).isEqualTo("127.0.0.1"); assertThat(node.getPort()).isEqualTo(7369); - assertThat(node.getType()).isEqualTo(NodeType.SLAVE); + assertThat(node.getType()).isEqualTo(NodeType.REPLICA); assertThat(node.getMasterId()).isEqualTo("ef570f86c7b1a953846668debc177a3a16733420"); assertThat(node.getSlotRange()).isNotNull(); - assertThat(node.getFlags()).contains(Flag.SLAVE); + assertThat(node.getFlags()).contains(Flag.REPLICA); assertThat(node.getLinkState()).isEqualTo(LinkState.CONNECTED); } 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 8188842937..17d9ca7314 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 @@ -65,7 +65,6 @@ import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.ValueEncoding.RedisValueEncoding; -import org.springframework.data.redis.connection.RedisListCommands.*; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.script.DigestUtils; @@ -122,7 +121,7 @@ void tearDown() throws IOException { try (Jedis jedis = pool.getResource()) { jedis.flushAll(); } catch (Exception e) { - // ignore this one since we cannot remove data from slaves + // ignore this one since we cannot remove data from replicas } } } @@ -234,26 +233,27 @@ public void clientListShouldGetInfosForAllClients() { } @Test // DATAREDIS-315 - public void clusterGetMasterSlaveMapShouldListMastersAndSlavesCorrectly() { + public void clusterGetMasterReplicaMapShouldListMastersAndReplicasCorrectly() { - Map> masterSlaveMap = clusterConnection.clusterGetMasterSlaveMap(); + Map> masterReplicaMap = clusterConnection + .clusterGetMasterReplicaMap(); - assertThat(masterSlaveMap).isNotNull(); - assertThat(masterSlaveMap.size()).isEqualTo(3); - assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT))) - .contains(new RedisClusterNode(CLUSTER_HOST, SLAVEOF_NODE_1_PORT)); - assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_2_PORT)).isEmpty()).isTrue(); - assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)).isEmpty()).isTrue(); + assertThat(masterReplicaMap).isNotNull(); + assertThat(masterReplicaMap.size()).isEqualTo(3); + assertThat(masterReplicaMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT))) + .contains(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT)); + assertThat(masterReplicaMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_2_PORT)).isEmpty()).isTrue(); + assertThat(masterReplicaMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)).isEmpty()).isTrue(); } @Test // DATAREDIS-315 - public void clusterGetSlavesShouldReturnSlaveCorrectly() { + public void clusterGetReplicasShouldReturnReplicaCorrectly() { - Set slaves = clusterConnection - .clusterGetSlaves(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT)); + Set replicas = clusterConnection + .clusterGetReplicas(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT)); - assertThat(slaves.size()).isEqualTo(1); - assertThat(slaves).contains(new RedisClusterNode(CLUSTER_HOST, SLAVEOF_NODE_1_PORT)); + assertThat(replicas.size()).isEqualTo(1); + assertThat(replicas).contains(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT)); } @Test // DATAREDIS-315 @@ -668,7 +668,7 @@ public void getClusterNodeForKeyShouldReturnNodeCorrectly() { @Test // DATAREDIS-315, DATAREDIS-661 public void getConfigShouldLoadConfigurationOfSpecificNode() { - Properties result = clusterConnection.getConfig(new RedisClusterNode(CLUSTER_HOST, SLAVEOF_NODE_1_PORT), "*"); + Properties result = clusterConnection.getConfig(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT), "*"); assertThat(result.getProperty("slaveof")).endsWith("7379"); } 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 index 454074f7a8..10ff91ebf4 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java @@ -257,10 +257,10 @@ void timeShouldBeExecutedOnArbitraryNode() { void shouldFailWithUnknownNode() { try { - connection.serverCommands().dbSize(new RedisClusterNode(CLUSTER_HOST, SLAVEOF_NODE_1_PORT)); + connection.serverCommands().dbSize(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT)); } catch (IllegalArgumentException e) { assertThat(e.getMessage()) - .contains("Node " + CLUSTER_HOST + ":" + SLAVEOF_NODE_1_PORT + " is unknown to cluster"); + .contains("Node " + CLUSTER_HOST + ":" + REPLICAOF_NODE_1_PORT + " is unknown to cluster"); } } 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 6c9676d737..fc2f7a67e4 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 @@ -103,21 +103,21 @@ public void getClientNameShouldSendRequestCorrectly() { } @Test // DATAREDIS-277 - void slaveOfShouldThrowExectpionWhenCalledForNullHost() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.slaveOf(null, 0)); + void replicaOfShouldThrowExectpionWhenCalledForNullHost() { + assertThatIllegalArgumentException().isThrownBy(() -> connection.replicaOf(null, 0)); } @Test // DATAREDIS-277 - public void slaveOfShouldBeSentCorrectly() { + public void replicaOfShouldBeSentCorrectly() { - connection.slaveOf("127.0.0.1", 1001); + connection.replicaOf("127.0.0.1", 1001); verifyNativeConnectionInvocation().slaveof(eq("127.0.0.1"), eq(1001)); } @Test // DATAREDIS-277 - public void slaveOfNoOneShouldBeSentCorrectly() { + public void replicaOfNoOneShouldBeSentCorrectly() { - connection.slaveOfNoOne(); + connection.replicaOfNoOne(); verifyNativeConnectionInvocation().slaveofNoOne(); } @@ -296,15 +296,15 @@ public void getClientNameShouldSendRequestCorrectly() { @Test @Override // DATAREDIS-277 - public void slaveOfShouldBeSentCorrectly() { + public void replicaOfShouldBeSentCorrectly() { assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(() -> super.slaveOfShouldBeSentCorrectly()); + .isThrownBy(() -> super.replicaOfShouldBeSentCorrectly()); } @Test // DATAREDIS-277 - public void slaveOfNoOneShouldBeSentCorrectly() { + public void replicaOfNoOneShouldBeSentCorrectly() { assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(() -> super.slaveOfNoOneShouldBeSentCorrectly()); + .isThrownBy(() -> super.replicaOfNoOneShouldBeSentCorrectly()); } @Test // DATAREDIS-531 diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnectionUnitTests.java index c87ce8ea03..b2de3507c8 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelConnectionUnitTests.java @@ -87,32 +87,32 @@ void mastersShouldReadMastersCorrectly() { } @Test // DATAREDIS-330 - void shouldReadSlavesCorrectly() { + void shouldReadReplicasCorrectly() { - connection.slaves("mymaster"); - verify(jedisMock, times(1)).sentinelSlaves(eq("mymaster")); + connection.replicas("mymaster"); + verify(jedisMock, times(1)).sentinelReplicas(eq("mymaster")); } @Test // DATAREDIS-330 - void shouldReadSlavesCorrectlyWhenGivenNamedNode() { + void shouldReadReplicasCorrectlyWhenGivenNamedNode() { - connection.slaves(new RedisNodeBuilder().withName("mymaster").build()); - verify(jedisMock, times(1)).sentinelSlaves(eq("mymaster")); + connection.replicas(new RedisNodeBuilder().withName("mymaster").build()); + verify(jedisMock, times(1)).sentinelReplicas(eq("mymaster")); } @Test // DATAREDIS-330 - void readSlavesShouldThrowExceptionWhenGivenEmptyMasterName() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.slaves("")); + void readReplicasShouldThrowExceptionWhenGivenEmptyMasterName() { + assertThatIllegalArgumentException().isThrownBy(() -> connection.replicas("")); } @Test // DATAREDIS-330 - void readSlavesShouldThrowExceptionWhenGivenNull() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.slaves((RedisNode) null)); + void readReplicasShouldThrowExceptionWhenGivenNull() { + assertThatIllegalArgumentException().isThrownBy(() -> connection.replicas((RedisNode) null)); } @Test // DATAREDIS-330 - void readSlavesShouldThrowExceptionWhenNodeWithoutName() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.slaves(new RedisNodeBuilder().build())); + void readReplicasShouldThrowExceptionWhenNodeWithoutName() { + assertThatIllegalArgumentException().isThrownBy(() -> connection.replicas(new RedisNodeBuilder().build())); } @Test // DATAREDIS-330 diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelIntegrationTests.java index c0adb6daca..5df6760d1f 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisSentinelIntegrationTests.java @@ -46,8 +46,8 @@ @EnabledOnRedisSentinelAvailable public class JedisSentinelIntegrationTests extends AbstractConnectionIntegrationTests { - private static final RedisServer SLAVE_0 = new RedisServer("127.0.0.1", 6380); - private static final RedisServer SLAVE_1 = new RedisServer("127.0.0.1", 6381); + private static final RedisServer REPLICA_0 = new RedisServer("127.0.0.1", 6380); + private static final RedisServer REPLICA_1 = new RedisServer("127.0.0.1", 6381); public JedisSentinelIntegrationTests(@RedisSentinel JedisConnectionFactory connectionFactory) { this.connectionFactory = connectionFactory; @@ -70,15 +70,15 @@ void shouldReadMastersCorrectly() { } @Test // DATAREDIS-330 - void shouldReadSlavesOfMastersCorrectly() { + void shouldReadReplicaOfMastersCorrectly() { RedisSentinelConnection sentinelConnection = connectionFactory.getSentinelConnection(); List servers = (List) sentinelConnection.masters(); assertThat(servers).hasSize(1); - Collection slaves = sentinelConnection.slaves(servers.get(0)); - assertThat(slaves).hasSize(2).contains(SLAVE_0, SLAVE_1); + Collection replicas = sentinelConnection.replicas(servers.get(0)); + assertThat(replicas).hasSize(2).contains(REPLICA_0, REPLICA_1); } @Test // DATAREDIS-552 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 72913a826e..e5d63fc334 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 @@ -285,26 +285,27 @@ public void clientListShouldGetInfosForAllClients() { } @Test // DATAREDIS-315 - public void clusterGetMasterSlaveMapShouldListMastersAndSlavesCorrectly() { + public void clusterGetMasterReplicaMapShouldListMastersAndReplicasCorrectly() { - Map> masterSlaveMap = clusterConnection.clusterGetMasterSlaveMap(); + Map> masterReplicaMap = clusterConnection + .clusterGetMasterReplicaMap(); - assertThat(masterSlaveMap).isNotNull(); - assertThat(masterSlaveMap).hasSize(3); - assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT))) - .contains(new RedisClusterNode(CLUSTER_HOST, SLAVEOF_NODE_1_PORT)); - assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_2_PORT)).isEmpty()).isTrue(); - assertThat(masterSlaveMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)).isEmpty()).isTrue(); + assertThat(masterReplicaMap).isNotNull(); + assertThat(masterReplicaMap).hasSize(3); + assertThat(masterReplicaMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT))) + .contains(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT)); + assertThat(masterReplicaMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_2_PORT)).isEmpty()).isTrue(); + assertThat(masterReplicaMap.get(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)).isEmpty()).isTrue(); } @Test // DATAREDIS-315 - public void clusterGetSlavesShouldReturnSlaveCorrectly() { + public void clusterGetReplicasShouldReturnReplicaCorrectly() { - Set slaves = clusterConnection - .clusterGetSlaves(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT)); + Set replicas = clusterConnection + .clusterGetReplicas(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_1_PORT)); - assertThat(slaves).hasSize(1); - assertThat(slaves).contains(new RedisClusterNode(CLUSTER_HOST, SLAVEOF_NODE_1_PORT)); + assertThat(replicas).hasSize(1); + assertThat(replicas).contains(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT)); } @Test // DATAREDIS-315 @@ -699,7 +700,7 @@ public void getClusterNodeForKeyShouldReturnNodeCorrectly() { @Test // DATAREDIS-315, DATAREDIS-661 public void getConfigShouldLoadConfigurationOfSpecificNode() { - Properties result = clusterConnection.getConfig(new RedisClusterNode(CLUSTER_HOST, SLAVEOF_NODE_1_PORT), "*"); + Properties result = clusterConnection.getConfig(new RedisClusterNode(CLUSTER_HOST, REPLICAOF_NODE_1_PORT), "*"); assertThat(result.getProperty("slaveof")).endsWith("7379"); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java index fcc6701725..530aa4ceca 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java @@ -426,7 +426,7 @@ void factoryUsesElastiCacheMasterReplicaConnections() { assumeTrue(String.format("No replicas connected to %s:%s.", SettingsUtils.getHost(), SettingsUtils.getPort()), connection.info("replication").getProperty("connected_slaves", "0").compareTo("0") > 0); - LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().readFrom(ReadFrom.SLAVE) + LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().readFrom(ReadFrom.REPLICA) .clientResources(LettuceTestClientResources.getSharedClientResources()).build(); RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration( diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java index c479a17e99..41bd3fd2ac 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java @@ -116,21 +116,21 @@ public void getClientNameShouldSendRequestCorrectly() { } @Test // DATAREDIS-277 - void slaveOfShouldThrowExectpionWhenCalledForNullHost() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.slaveOf(null, 0)); + void replicaOfShouldThrowExectpionWhenCalledForNullHost() { + assertThatIllegalArgumentException().isThrownBy(() -> connection.replicaOf(null, 0)); } @Test // DATAREDIS-277 - public void slaveOfShouldBeSentCorrectly() { + public void replicaOfShouldBeSentCorrectly() { - connection.slaveOf("127.0.0.1", 1001); + connection.replicaOf("127.0.0.1", 1001); verify(syncCommandsMock, times(1)).slaveof(eq("127.0.0.1"), eq(1001)); } @Test // DATAREDIS-277 - public void slaveOfNoOneShouldBeSentCorrectly() { + public void replicaOfNoOneShouldBeSentCorrectly() { - connection.slaveOfNoOne(); + connection.replicaOfNoOne(); verify(syncCommandsMock, times(1)).slaveofNoOne(); } @@ -280,9 +280,9 @@ public void shutdownWithNosaveOptionIsCalledCorrectly() { } @Test // DATAREDIS-528 - public void slaveOfShouldBeSentCorrectly() { + public void replicaOfShouldBeSentCorrectly() { - connection.slaveOf("127.0.0.1", 1001); + connection.replicaOf("127.0.0.1", 1001); verify(asyncCommandsMock, times(1)).slaveof(eq("127.0.0.1"), eq(1001)); } @@ -302,9 +302,9 @@ public void killClientShouldDelegateCallCorrectly() { } @Test // DATAREDIS-528 - public void slaveOfNoOneShouldBeSentCorrectly() { + public void replicaOfNoOneShouldBeSentCorrectly() { - connection.slaveOfNoOne(); + connection.replicaOfNoOne(); verify(asyncCommandsMock, times(1)).slaveofNoOne(); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterCommandsIntegrationTests.java index af97e1ea62..847ee35920 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterCommandsIntegrationTests.java @@ -60,11 +60,11 @@ void clusterGetNodesShouldReturnNodes() { } @Test // DATAREDIS-1150 - void clusterGetSlavesShouldReturnNodes() { + void clusterGetReplicasShouldReturnNodes() { connection.clusterGetNodes().filter(RedisClusterNode::isMaster) .filter(node -> (node.getPort() == 7379 || node.getPort() == 7382)) - .flatMap(it -> connection.clusterGetSlaves(it)) // + .flatMap(it -> connection.clusterGetReplicas(it)) // .collectList() // .as(StepVerifier::create) // .consumeNextWith(actual -> { @@ -74,9 +74,9 @@ void clusterGetSlavesShouldReturnNodes() { } @Test // DATAREDIS-1150 - void clusterGetMasterSlaveMapShouldReportTopology() { + void clusterGetMasterReplicaMapShouldReportTopology() { - connection.clusterGetMasterSlaveMap() // + connection.clusterGetMasterReplicaMap() // .as(StepVerifier::create) // .consumeNextWith(actual -> { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java index 8e5de642d8..248c945859 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnectionUnitTests.java @@ -97,7 +97,7 @@ void mastersShouldReadMastersCorrectly() { } @Test // DATAREDIS-348 - void shouldReadSlavesCorrectly() { + void shouldReadReplicasCorrectly() { when(sentinelCommandsMock.slaves(MASTER_ID)).thenReturn(Collections.> emptyList()); connection.slaves(MASTER_ID); @@ -105,26 +105,26 @@ void shouldReadSlavesCorrectly() { } @Test // DATAREDIS-348 - void shouldReadSlavesCorrectlyWhenGivenNamedNode() { + void shouldReadReplicasCorrectlyWhenGivenNamedNode() { when(sentinelCommandsMock.slaves(MASTER_ID)).thenReturn(Collections.> emptyList()); - connection.slaves(new RedisNodeBuilder().withName(MASTER_ID).build()); + connection.replicas(new RedisNodeBuilder().withName(MASTER_ID).build()); verify(sentinelCommandsMock, times(1)).slaves(eq(MASTER_ID)); } @Test // DATAREDIS-348 - void readSlavesShouldThrowExceptionWhenGivenEmptyMasterName() { + void readReplicasShouldThrowExceptionWhenGivenEmptyMasterName() { assertThatIllegalArgumentException().isThrownBy(() -> connection.slaves("")); } @Test // DATAREDIS-348 - void readSlavesShouldThrowExceptionWhenGivenNull() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.slaves((RedisNode) null)); + void readReplicasShouldThrowExceptionWhenGivenNull() { + assertThatIllegalArgumentException().isThrownBy(() -> connection.replicas((RedisNode) null)); } @Test // DATAREDIS-348 - void readSlavesShouldThrowExceptionWhenNodeWithoutName() { - assertThatIllegalArgumentException().isThrownBy(() -> connection.slaves(new RedisNodeBuilder().build())); + void readReplicasShouldThrowExceptionWhenNodeWithoutName() { + assertThatIllegalArgumentException().isThrownBy(() -> connection.replicas(new RedisNodeBuilder().build())); } @Test // DATAREDIS-348 diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java index cd3927b841..82c54fedde 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java @@ -56,8 +56,8 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati private static final RedisServer SENTINEL_0 = new RedisServer("127.0.0.1", 26379); private static final RedisServer SENTINEL_1 = new RedisServer("127.0.0.1", 26380); - private static final RedisServer SLAVE_0 = new RedisServer("127.0.0.1", 6380); - private static final RedisServer SLAVE_1 = new RedisServer("127.0.0.1", 6381); + private static final RedisServer REPLICA_0 = new RedisServer("127.0.0.1", 6380); + private static final RedisServer REPLICA_1 = new RedisServer("127.0.0.1", 6381); private static final RedisSentinelConfiguration SENTINEL_CONFIG; static { @@ -159,15 +159,15 @@ void reactiveShouldUseSpecifiedDatabase() { @Test // DATAREDIS-348 - void shouldReadSlavesOfMastersCorrectly() { + void shouldReadReplicasOfMastersCorrectly() { RedisSentinelConnection sentinelConnection = connectionFactory.getSentinelConnection(); List servers = (List) sentinelConnection.masters(); assertThat(servers.size()).isEqualTo(1); - Collection slaves = sentinelConnection.slaves(servers.get(0)); - assertThat(slaves).containsAnyOf(SLAVE_0, SLAVE_1); + Collection replicas = sentinelConnection.replicas(servers.get(0)); + assertThat(replicas).containsAnyOf(REPLICA_0, REPLICA_1); } @Test // DATAREDIS-462 @@ -228,10 +228,10 @@ void factoryWithReadFromMasterSettings() { } @Test // DATAREDIS-580 - void factoryWithReadFromSlaveSettings() { + void factoryWithReadFromReplicaSettings() { LettuceConnectionFactory factory = new LettuceConnectionFactory(SENTINEL_CONFIG, - LettuceTestClientConfiguration.builder().readFrom(ReadFrom.SLAVE).build()); + LettuceTestClientConfiguration.builder().readFrom(ReadFrom.REPLICA).build()); factory.afterPropertiesSet(); ConnectionFactoryTracker.add(factory); @@ -247,7 +247,7 @@ void factoryWithReadFromSlaveSettings() { } @Test // DATAREDIS-580 - void factoryUsesMasterSlaveConnections() { + void factoryUsesMasterReplicaConnections() { LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().readFrom(ReadFrom.SLAVE) .build(); diff --git a/src/test/java/org/springframework/data/redis/core/DefaultClusterOperationsUnitTests.java b/src/test/java/org/springframework/data/redis/core/DefaultClusterOperationsUnitTests.java index 97dc03c84c..47ff2d0ba6 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultClusterOperationsUnitTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultClusterOperationsUnitTests.java @@ -214,16 +214,16 @@ void flushDbShouldThrowExceptionWhenNodeIsNull() { } @Test // DATAREDIS-315 - void getSlavesShouldDelegateToConnection() { + void getReplicasShouldDelegateToConnection() { - clusterOps.getSlaves(NODE_1); + clusterOps.getReplicas(NODE_1); - verify(connection, times(1)).clusterGetSlaves(eq(NODE_1)); + verify(connection, times(1)).clusterGetReplicas(eq(NODE_1)); } @Test // DATAREDIS-315 - void getSlavesShouldThrowExceptionWhenNodeIsNull() { - assertThatIllegalArgumentException().isThrownBy(() -> clusterOps.getSlaves(null)); + void getReplicasShouldThrowExceptionWhenNodeIsNull() { + assertThatIllegalArgumentException().isThrownBy(() -> clusterOps.getReplicas(null)); } @Test // DATAREDIS-315 diff --git a/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java b/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java index 396efb5bb3..fc4da6de8d 100644 --- a/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java +++ b/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java @@ -60,17 +60,17 @@ void setUp() { } @Test // DATAREDIS-277 - void slaveOfIsDelegatedToConnectionCorrectly() { + void replicaOfIsDelegatedToConnectionCorrectly() { - template.slaveOf("127.0.0.1", 1001); - verify(redisConnectionMock, times(1)).slaveOf(eq("127.0.0.1"), eq(1001)); + template.replicaOf("127.0.0.1", 1001); + verify(redisConnectionMock, times(1)).replicaOf(eq("127.0.0.1"), eq(1001)); } @Test // DATAREDIS-277 - void slaveOfNoOneIsDelegatedToConnectionCorrectly() { + void replicaOfNoOneIsDelegatedToConnectionCorrectly() { - template.slaveOfNoOne(); - verify(redisConnectionMock, times(1)).slaveOfNoOne(); + template.replicaOfNoOne(); + verify(redisConnectionMock, times(1)).replicaOfNoOne(); } @Test // DATAREDIS-501 From c2c76b2a945d93478ab6959de43261267b7396fc Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 22 Feb 2022 15:02:49 +0100 Subject: [PATCH 03/12] Remove deprecated LettucePool and deprecated methods. --- .../lettuce/AuthenticatingRedisClient.java | 52 --- .../lettuce/DefaultLettucePool.java | 371 ------------------ .../lettuce/LettuceClusterConnection.java | 2 +- .../connection/lettuce/LettuceConnection.java | 88 +---- .../lettuce/LettuceConnectionFactory.java | 22 +- .../connection/lettuce/LettuceConverters.java | 197 +--------- .../lettuce/LettuceExceptionConverter.java | 2 + .../lettuce/LettuceFutureUtils.java | 2 +- .../redis/connection/lettuce/LettucePool.java | 41 -- .../LettuceReactiveRedisConnection.java | 2 +- .../lettuce/LettuceSentinelConnection.java | 2 +- .../AuthenticatingRedisClientTests.java | 110 ------ .../lettuce/DefaultLettucePoolTests.java | 195 --------- .../LettuceConnectionFactoryTests.java | 17 - .../LettuceConnectionIntegrationTests.java | 99 ----- .../lettuce/LettuceConnectionUnitTests.java | 6 +- 16 files changed, 18 insertions(+), 1190 deletions(-) delete mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java delete mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java delete mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java delete mode 100644 src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java delete mode 100644 src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java b/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java deleted file mode 100644 index b528904937..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClient.java +++ /dev/null @@ -1,52 +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.lettuce; - -import io.lettuce.core.RedisClient; -import io.lettuce.core.RedisURI; -import io.lettuce.core.api.StatefulRedisConnection; -import io.lettuce.core.codec.RedisCodec; -import io.lettuce.core.pubsub.StatefulRedisPubSubConnection; - -/** - * Extension of {@link RedisClient} that calls auth on all new connections using the supplied credentials - * - * @author Jennifer Hickey - * @author Mark Paluch - * @author Christoph Strobl - * @deprecated since 1.6 - Please use {@link RedisURI#setPassword(String)} - */ -@Deprecated -public class AuthenticatingRedisClient extends RedisClient { - - public AuthenticatingRedisClient(String host, int port, String password) { - super(null, RedisURI.builder().withHost(host).withPort(port).withPassword(password).build()); - } - - public AuthenticatingRedisClient(String host, String password) { - super(null, RedisURI.builder().withHost(host).withPassword(password).build()); - } - - @Override - public StatefulRedisConnection connect(RedisCodec codec) { - return super.connect(codec); - } - - @Override - public StatefulRedisPubSubConnection connectPubSub(RedisCodec codec) { - return super.connectPubSub(codec); - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java deleted file mode 100644 index 9b9dc39958..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java +++ /dev/null @@ -1,371 +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.lettuce; - -import io.lettuce.core.RedisClient; -import io.lettuce.core.RedisURI; -import io.lettuce.core.api.StatefulConnection; -import io.lettuce.core.api.StatefulRedisConnection; -import io.lettuce.core.resource.ClientResources; - -import java.time.Duration; - -import org.apache.commons.pool2.BasePooledObjectFactory; -import org.apache.commons.pool2.PooledObject; -import org.apache.commons.pool2.impl.DefaultPooledObject; -import org.apache.commons.pool2.impl.GenericObjectPool; -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.data.redis.connection.PoolException; -import org.springframework.data.redis.connection.RedisSentinelConfiguration; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Default implementation of {@link LettucePool}. - * - * @author Jennifer Hickey - * @author Christoph Strobl - * @author Mark Paluch - * @deprecated since 2.0, use pooling via {@link LettucePoolingClientConfiguration}. - */ -@Deprecated -public class DefaultLettucePool implements LettucePool, InitializingBean { - - @SuppressWarnings("rawtypes") // - private @Nullable GenericObjectPool> internalPool; - private @Nullable RedisClient client; - private int dbIndex = 0; - private GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); - private String hostName = "localhost"; - private int port = 6379; - private @Nullable String password; - private long timeout = Duration.ofMinutes(1).toMillis(); - private @Nullable RedisSentinelConfiguration sentinelConfiguration; - private @Nullable ClientResources clientResources; - - /** - * Constructs a new DefaultLettucePool instance with default settings. - */ - public DefaultLettucePool() {} - - /** - * Uses the {@link GenericObjectPoolConfig} defaults for configuring the connection pool - * - * @param hostName The Redis host - * @param port The Redis port - */ - public DefaultLettucePool(String hostName, int port) { - this.hostName = hostName; - this.port = port; - } - - /** - * Uses the {@link RedisSentinelConfiguration} and {@link RedisClient} defaults for configuring the connection pool - * based on sentinels. - * - * @param sentinelConfiguration The Sentinel configuration - * @since 1.6 - */ - public DefaultLettucePool(RedisSentinelConfiguration sentinelConfiguration) { - this.sentinelConfiguration = sentinelConfiguration; - } - - /** - * Uses the {@link RedisClient} defaults for configuring the connection pool - * - * @param hostName The Redis host - * @param port The Redis port - * @param poolConfig The pool {@link GenericObjectPoolConfig} - */ - public DefaultLettucePool(String hostName, int port, GenericObjectPoolConfig poolConfig) { - this.hostName = hostName; - this.port = port; - this.poolConfig = poolConfig; - } - - /** - * @return true when {@link RedisSentinelConfiguration} is present. - * @since 1.6 - */ - public boolean isRedisSentinelAware() { - return sentinelConfiguration != null; - } - - @SuppressWarnings({ "rawtypes" }) - public void afterPropertiesSet() { - - if (clientResources != null) { - this.client = RedisClient.create(clientResources, getRedisURI()); - } else { - this.client = RedisClient.create(getRedisURI()); - } - - client.setDefaultTimeout(Duration.ofMillis(timeout)); - this.internalPool = new GenericObjectPool<>(new LettuceFactory(client, dbIndex), poolConfig); - } - - /** - * @return a RedisURI pointing either to a single Redis host or containing a set of sentinels. - */ - private RedisURI getRedisURI() { - - RedisURI redisUri = isRedisSentinelAware() - ? LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration) : createSimpleHostRedisURI(); - - if (StringUtils.hasText(password)) { - redisUri.setPassword(password); - } - - return redisUri; - } - - private RedisURI createSimpleHostRedisURI() { - return RedisURI.Builder.redis(hostName, port).withTimeout(Duration.ofMillis(timeout)).build(); - } - - @Override - @SuppressWarnings("unchecked") - public StatefulConnection getResource() { - try { - return internalPool.borrowObject(); - } catch (Exception e) { - throw new PoolException("Could not get a resource from the pool", e); - } - } - - @Override - public void returnBrokenResource(final StatefulConnection resource) { - - try { - internalPool.invalidateObject(resource); - } catch (Exception e) { - throw new PoolException("Could not invalidate the broken resource", e); - } - } - - @Override - public void returnResource(final StatefulConnection resource) { - - try { - internalPool.returnObject(resource); - } catch (Exception e) { - throw new PoolException("Could not return the resource to the pool", e); - } - } - - @Override - public void destroy() { - - try { - client.shutdown(); - internalPool.close(); - } catch (Exception e) { - throw new PoolException("Could not destroy the pool", e); - } - } - - /** - * @return The Redis client - */ - @Override - @Nullable - public RedisClient getClient() { - return client; - } - - /** - * @return The pool configuration - */ - public GenericObjectPoolConfig getPoolConfig() { - return poolConfig; - } - - /** - * @param poolConfig The pool configuration to use - */ - public void setPoolConfig(GenericObjectPoolConfig poolConfig) { - this.poolConfig = poolConfig; - } - - /** - * Returns the index of the database. - * - * @return Returns the database index - */ - public int getDatabase() { - return dbIndex; - } - - /** - * Sets the index of the database used by this connection pool. Default is 0. - * - * @param index database index - */ - public void setDatabase(int index) { - Assert.isTrue(index >= 0, "invalid DB index (a positive index required)"); - this.dbIndex = index; - } - - /** - * Returns the password used for authenticating with the Redis server. - * - * @return password for authentication - */ - @Nullable - public String getPassword() { - return password; - } - - /** - * Sets the password used for authenticating with the Redis server. - * - * @param password the password to set - */ - public void setPassword(String password) { - this.password = password; - } - - /** - * Returns the current host. - * - * @return the host - */ - public String getHostName() { - return hostName; - } - - /** - * Sets the host. - * - * @param host the host to set - */ - public void setHostName(String host) { - this.hostName = host; - } - - /** - * Returns the current port. - * - * @return the port - */ - public int getPort() { - return port; - } - - /** - * Sets the port. - * - * @param port the port to set - */ - public void setPort(int port) { - this.port = port; - } - - /** - * Returns the connection timeout (in milliseconds). - * - * @return connection timeout - */ - public long getTimeout() { - return timeout; - } - - /** - * Sets the connection timeout (in milliseconds). - * - * @param timeout connection timeout - */ - public void setTimeout(long timeout) { - this.timeout = timeout; - } - - /** - * Get the {@link ClientResources} to reuse infrastructure. - * - * @return {@literal null} if not set. - * @since 1.7 - */ - @Nullable - public ClientResources getClientResources() { - return clientResources; - } - - /** - * Sets the {@link ClientResources} to reuse the client infrastructure.
- * Set to {@literal null} to not share resources. - * - * @param clientResources can be {@literal null}. - * @since 1.7 - */ - public void setClientResources(ClientResources clientResources) { - this.clientResources = clientResources; - } - - @SuppressWarnings("rawtypes") - private static class LettuceFactory extends BasePooledObjectFactory> { - - private final RedisClient client; - - private int dbIndex; - - public LettuceFactory(RedisClient client, int dbIndex) { - super(); - this.client = client; - this.dbIndex = dbIndex; - } - - @Override - public void activateObject(PooledObject> pooledObject) throws Exception { - - if (pooledObject.getObject() instanceof StatefulRedisConnection) { - ((StatefulRedisConnection) pooledObject.getObject()).sync().select(dbIndex); - } - } - - @Override - public void destroyObject(final PooledObject> obj) throws Exception { - try { - obj.getObject().close(); - } catch (Exception e) { - // Errors may happen if returning a broken resource - } - } - - @Override - public boolean validateObject(final PooledObject> obj) { - try { - if (obj.getObject() instanceof StatefulRedisConnection) { - ((StatefulRedisConnection) obj.getObject()).sync().ping(); - } - return true; - } catch (Exception e) { - return false; - } - } - - @Override - public StatefulConnection create() throws Exception { - return client.connect(LettuceConnection.CODEC); - } - - @Override - public PooledObject> wrap(StatefulConnection obj) { - return new DefaultPooledObject<>(obj); - } - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index b4b4ffd71d..eb858bd370 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -61,7 +61,7 @@ public class LettuceClusterConnection extends LettuceConnection implements DefaultedRedisClusterConnection { static final ExceptionTranslationStrategy exceptionConverter = new PassThroughExceptionTranslationStrategy( - new LettuceExceptionConverter()); + LettuceExceptionConverter.INSTANCE); private final Log log = LogFactory.getLog(getClass()); 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 f40539b590..b34c959332 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 @@ -49,7 +49,6 @@ import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -93,7 +92,7 @@ public class LettuceConnection extends AbstractRedisConnection { static final RedisCodec CODEC = ByteArrayCodec.INSTANCE; private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy( - LettuceConverters.exceptionConverter()); + LettuceExceptionConverter.INSTANCE); private static final TypeHints typeHints = new TypeHints(); private final int defaultDbIndex; @@ -161,20 +160,7 @@ public List convert(List execResults) { * @param client The {@link RedisClient} to use when instantiating a native connection */ public LettuceConnection(long timeout, RedisClient client) { - this(null, timeout, client, null); - } - - /** - * Instantiates a new lettuce connection. - * - * @param timeout The connection timeout (in milliseconds) * @param client The {@link RedisClient} to use when - * instantiating a pub/sub connection - * @param pool The connection pool to use for all other native connections - * @deprecated since 2.0, use pooling via {@link LettucePoolingClientConfiguration}. - */ - @Deprecated - public LettuceConnection(long timeout, RedisClient client, LettucePool pool) { - this(null, timeout, client, pool); + this(null, timeout, client); } /** @@ -187,25 +173,7 @@ public LettuceConnection(long timeout, RedisClient client, LettucePool pool) { */ public LettuceConnection(@Nullable StatefulRedisConnection sharedConnection, long timeout, RedisClient client) { - this(sharedConnection, timeout, client, null); - } - - /** - * Instantiates a new lettuce connection. - * - * @param sharedConnection A native connection that is shared with other {@link LettuceConnection}s. Should not be - * used for transactions or blocking operations - * @param timeout The connection timeout (in milliseconds) - * @param client The {@link RedisClient} to use when making pub/sub connections - * @param pool The connection pool to use for blocking and tx operations - * @deprecated since 2.0, use - * {@link #LettuceConnection(StatefulRedisConnection, LettuceConnectionProvider, long, int)} - */ - @Deprecated - public LettuceConnection(@Nullable StatefulRedisConnection sharedConnection, long timeout, - RedisClient client, @Nullable LettucePool pool) { - - this(sharedConnection, timeout, client, pool, 0); + this(sharedConnection, timeout, client, 0); } /** @@ -213,22 +181,13 @@ public LettuceConnection(@Nullable StatefulRedisConnection share * used for transactions or blocking operations. * @param timeout The connection timeout (in milliseconds) * @param client The {@link RedisClient} to use when making pub/sub connections. - * @param pool The connection pool to use for blocking and tx operations. * @param defaultDbIndex The db index to use along with {@link RedisClient} when establishing a dedicated connection. * @since 1.7 - * @deprecated since 2.0, use - * {@link #LettuceConnection(StatefulRedisConnection, LettuceConnectionProvider, long, int)} */ - @Deprecated public LettuceConnection(@Nullable StatefulRedisConnection sharedConnection, long timeout, - @Nullable AbstractRedisClient client, @Nullable LettucePool pool, int defaultDbIndex) { - - if (pool != null) { - this.connectionProvider = new LettucePoolConnectionProvider(pool); - } else { - this.connectionProvider = new StandaloneConnectionProvider((RedisClient) client, CODEC); - } + @Nullable AbstractRedisClient client, int defaultDbIndex) { + this.connectionProvider = new StandaloneConnectionProvider((RedisClient) client, CODEC); this.asyncSharedConn = sharedConnection; this.timeout = timeout; this.defaultDbIndex = defaultDbIndex; @@ -1248,43 +1207,6 @@ public CommandOutput getTypeHint(ProtocolKeyword type, CommandOutput defaultType } } - static class LettucePoolConnectionProvider implements LettuceConnectionProvider { - - private final LettucePool pool; - - LettucePoolConnectionProvider(LettucePool pool) { - this.pool = pool; - } - - @Override - public > T getConnection(Class connectionType) { - return connectionType.cast(pool.getResource()); - } - - @Override - public > CompletionStage getConnectionAsync(Class connectionType) { - throw new UnsupportedOperationException("Async operations not supported!"); - } - - @Override - @SuppressWarnings("unchecked") - public void release(StatefulConnection connection) { - - if (connection.isOpen()) { - - if (connection instanceof StatefulRedisConnection) { - StatefulRedisConnection redisConnection = (StatefulRedisConnection) connection; - if (redisConnection.isMulti()) { - redisConnection.async().discard(); - } - } - pool.returnResource((StatefulConnection) connection); - } else { - pool.returnBrokenResource((StatefulConnection) connection); - } - } - } - /** * Strategy interface to control pipelining flush behavior. Lettuce writes (flushes) each command individually to the * Redis connection. Flushing behavior can be customized to optimize for performance. Flushing can be either stateless diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index 796e638127..e84bcc244d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -104,7 +104,7 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory, ReactiveRedisConnectionFactory { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy( - LettuceConverters.exceptionConverter()); + LettuceExceptionConverter.INSTANCE); private final Log log = LogFactory.getLog(getClass()); private final LettuceClientConfiguration clientConfiguration; @@ -117,7 +117,6 @@ public class LettuceConnectionFactory private boolean eagerInitialization = false; private @Nullable SharedConnection connection; private @Nullable SharedConnection reactiveConnection; - private @Nullable LettucePool pool; /** Synchronization monitor for the shared Connection */ private final Object connectionMonitor = new Object(); private boolean convertPipelineAndTxResults = true; @@ -198,17 +197,6 @@ public LettuceConnectionFactory(RedisClusterConfiguration clusterConfiguration) this(clusterConfiguration, new MutableLettuceClientConfiguration()); } - /** - * @param pool - * @deprecated since 2.0, use pooling via {@link LettucePoolingClientConfiguration}. - */ - @Deprecated - public LettuceConnectionFactory(LettucePool pool) { - - this(new MutableLettuceClientConfiguration()); - this.pool = pool; - } - /** * Constructs a new {@link LettuceConnectionFactory} instance using the given {@link RedisStandaloneConfiguration} and * {@link LettuceClientConfiguration}. @@ -405,8 +393,8 @@ public RedisConnection getConnection() { return getClusterConnection(); } - LettuceConnection connection; - connection = doCreateLettuceConnection(getSharedConnection(), connectionProvider, getTimeout(), getDatabase()); + LettuceConnection connection = doCreateLettuceConnection(getSharedConnection(), connectionProvider, getTimeout(), + getDatabase()); connection.setConvertPipelineAndTxResults(convertPipelineAndTxResults); return connection; } @@ -1095,10 +1083,6 @@ protected StatefulConnection getSharedReactiveConnection private LettuceConnectionProvider createConnectionProvider(AbstractRedisClient client, RedisCodec codec) { - if (this.pool != null) { - return new LettucePoolConnectionProvider(this.pool); - } - LettuceConnectionProvider connectionProvider = doCreateConnectionProvider(client, codec); if (this.clientConfiguration instanceof LettucePoolingClientConfiguration) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 72b36d612c..72ed8491ff 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -22,14 +22,12 @@ import io.lettuce.core.cluster.models.partitions.Partitions; import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.springframework.core.convert.converter.Converter; -import org.springframework.dao.DataAccessException; import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResult; import org.springframework.data.geo.GeoResults; @@ -53,7 +51,6 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.convert.Converters; -import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.data.redis.connection.convert.LongToBooleanConverter; import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; import org.springframework.data.redis.core.KeyScanOptions; @@ -65,7 +62,6 @@ 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.data.redis.util.ByteUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -84,12 +80,9 @@ * @author Chris Bono * @author Vikas Garg */ +@SuppressWarnings("ConstantConditions") public abstract class LettuceConverters extends Converters { - private static final Converter EXCEPTION_CONVERTER = new LettuceExceptionConverter(); - private static final ListConverter GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER; - private static final ListConverter, Object> KEY_VALUE_LIST_UNWRAPPER; - public static final byte[] PLUS_BYTES; public static final byte[] MINUS_BYTES; public static final byte[] POSITIVE_INFINITY_BYTES; @@ -104,31 +97,6 @@ public abstract class LettuceConverters extends Converters { MINUS_BYTES = toBytes("-"); POSITIVE_INFINITY_BYTES = toBytes("+inf"); NEGATIVE_INFINITY_BYTES = toBytes("-inf"); - - GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER = new ListConverter<>(LettuceConverters::geoCoordinatesToPoint); - - KEY_VALUE_LIST_UNWRAPPER = new ListConverter<>(source -> source.getValueOrElse(null)); - } - - @Deprecated - public static List toTuple(List source) { - - if (CollectionUtils.isEmpty(source)) { - return Collections.emptyList(); - } - - List tuples = new ArrayList<>(); - Iterator it = source.iterator(); - while (it.hasNext()) { - tuples.add(new DefaultTuple(it.next(), it.hasNext() ? Double.valueOf(toString(it.next())) : null)); - } - - return tuples; - } - - @Deprecated - public static Converter, List> bytesListToTupleListConverter() { - return LettuceConverters::toTuple; } public static Point geoCoordinatesToPoint(@Nullable GeoCoordinates geoCoordinate) { @@ -140,41 +108,6 @@ public static Converter> stringToRedisClientListCo return LettuceConverters::toListOfRedisClientInformation; } - @Deprecated - public static Converter dateToLong() { - return LettuceConverters::toLong; - } - - @Deprecated - public static Converter, Set> bytesListToBytesSet() { - return LettuceConverters::toBytesSet; - } - - @Deprecated - public static Converter bytesToString() { - return LettuceConverters::toString; - } - - @Deprecated - public static Converter, List> keyValueToBytesList() { - return LettuceConverters::toBytesList; - } - - @Deprecated - public static Converter, List> bytesSetToBytesList() { - return LettuceConverters::toBytesList; - } - - @Deprecated - public static Converter, List> bytesCollectionToBytesList() { - return LettuceConverters::toBytesList; - } - - @Deprecated - public static Converter>, Set> scoredValuesToTupleSet() { - return LettuceConverters::toTupleSet; - } - public static Converter>, List> scoredValuesToTupleList() { return source -> { @@ -189,16 +122,6 @@ public static Converter>, List> scoredValuesToTu }; } - @Deprecated - public static Converter, Tuple> scoredValueToTuple() { - return LettuceConverters::toTuple; - } - - @Deprecated - public static Converter exceptionConverter() { - return EXCEPTION_CONVERTER; - } - /** * @return * @sice 1.3 @@ -234,18 +157,6 @@ public static List toBytesList(Collection source) { return source != null ? new ArrayList<>(source) : null; } - @Deprecated - public static Set toTupleSet(@Nullable List> source) { - if (source == null) { - return null; - } - Set tuples = new LinkedHashSet<>(source.size()); - for (ScoredValue value : source) { - tuples.add(LettuceConverters.toTuple(value)); - } - return tuples; - } - public static Tuple toTuple(@Nullable ScoredValue source) { return source != null && source.hasValue() ? new DefaultTuple(source.getValue(), Double.valueOf(source.getScore())) : null; @@ -300,11 +211,6 @@ public static Map toMap(List source) { return target; } - @Deprecated - public static Converter, Map> bytesListToMapConverter() { - return LettuceConverters::toMap; - } - public static SortArgs toSortArgs(SortParameters params) { SortArgs args = new SortArgs(); @@ -346,28 +252,6 @@ public static List toListOfRedisClientInformation(String client return StringToRedisClientInfoConverter.INSTANCE.convert(clientList.split("\\r?\\n")); } - @Deprecated - public static byte[][] subarray(byte[][] input, int index) { - - if (input.length > index) { - byte[][] output = new byte[input.length - index][]; - System.arraycopy(input, index, output, 0, output.length); - return output; - } - - return null; - } - - @Deprecated - public static String boundaryToStringForZRange(Boundary boundary, String defaultValue) { - - if (boundary == null || boundary.getValue() == null) { - return defaultValue; - } - - return boundaryToString(boundary, "", "("); - } - private static String boundaryToString(Boundary boundary, String inclPrefix, String exclPrefix) { String prefix = boundary.isIncluding() ? inclPrefix : exclPrefix; @@ -639,66 +523,6 @@ public static byte[] toBytes(Double source) { return toBytes(String.valueOf(source)); } - /** - * Converts a given {@link Boundary} to its binary representation suitable for {@literal ZRANGEBY*} commands, despite - * {@literal ZRANGEBYLEX}. - * - * @param boundary - * @param defaultValue - * @return - * @since 1.6 - */ - @Deprecated - public static String boundaryToBytesForZRange(Boundary boundary, byte[] defaultValue) { - - if (boundary == null || boundary.getValue() == null) { - return toString(defaultValue); - } - - return boundaryToBytes(boundary, new byte[] {}, toBytes("(")); - } - - /** - * Converts a given {@link Boundary} to its binary representation suitable for ZRANGEBYLEX command. - * - * @param boundary - * @return - * @since 1.6 - */ - @Deprecated - public static String boundaryToBytesForZRangeByLex(Boundary boundary, byte[] defaultValue) { - - if (boundary == null || boundary.getValue() == null) { - return toString(defaultValue); - } - - return boundaryToBytes(boundary, toBytes("["), toBytes("(")); - } - - private static String boundaryToBytes(Boundary boundary, byte[] inclPrefix, byte[] exclPrefix) { - - byte[] prefix = boundary.isIncluding() ? inclPrefix : exclPrefix; - byte[] value = null; - if (boundary.getValue() instanceof byte[]) { - value = (byte[]) boundary.getValue(); - } else if (boundary.getValue() instanceof Double) { - value = toBytes((Double) boundary.getValue()); - } else if (boundary.getValue() instanceof Long) { - value = toBytes((Long) boundary.getValue()); - } else if (boundary.getValue() instanceof Integer) { - value = toBytes((Integer) boundary.getValue()); - } else if (boundary.getValue() instanceof String) { - value = toBytes((String) boundary.getValue()); - } else { - throw new IllegalArgumentException(String.format("Cannot convert %s to binary format", boundary.getValue())); - } - - ByteBuffer buffer = ByteBuffer.allocate(prefix.length + value.length); - buffer.put(prefix); - buffer.put(value); - return toString(ByteUtils.getBytes(buffer)); - } - public static List partitionsToClusterNodes(@Nullable Partitions source) { if (source == null) { @@ -1051,25 +875,6 @@ public static Converter>, GeoResults> return GeoResultsConverterFactory.INSTANCE.forMetric(metric); } - /** - * @return - * @since 1.8 - */ - @Deprecated - public static ListConverter geoCoordinatesToPointConverter() { - return GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER; - } - - /** - * @return - * @since 2.0 - */ - @SuppressWarnings("unchecked") - @Deprecated - public static ListConverter, V> keyValueListUnwrapper() { - return (ListConverter) KEY_VALUE_LIST_UNWRAPPER; - } - public static Converter> transactionResultUnwrapper() { return transactionResult -> transactionResult.stream().collect(Collectors.toList()); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceExceptionConverter.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceExceptionConverter.java index 7d636a2926..c4a9e4095d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceExceptionConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceExceptionConverter.java @@ -40,6 +40,8 @@ */ public class LettuceExceptionConverter implements Converter { + static final LettuceExceptionConverter INSTANCE = new LettuceExceptionConverter(); + public DataAccessException convert(Exception ex) { if (ex instanceof ExecutionException || ex instanceof RedisCommandExecutionException) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceFutureUtils.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceFutureUtils.java index 99cad3730c..784fe6253a 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceFutureUtils.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceFutureUtils.java @@ -71,7 +71,7 @@ static T join(CompletionStage future) throws RuntimeException, Completion Throwable exceptionToUse = e; if (e instanceof CompletionException) { - exceptionToUse = new LettuceExceptionConverter().convert((Exception) e.getCause()); + exceptionToUse = LettuceExceptionConverter.INSTANCE.convert((Exception) e.getCause()); if (exceptionToUse == null) { exceptionToUse = e.getCause(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java deleted file mode 100644 index af41bfbacc..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java +++ /dev/null @@ -1,41 +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.lettuce; - -import io.lettuce.core.AbstractRedisClient; -import io.lettuce.core.api.StatefulConnection; - -import org.springframework.data.redis.connection.Pool; -import org.springframework.lang.Nullable; - -/** - * Pool of Lettuce {@link StatefulConnection}s - * - * @author Jennifer Hickey - * @author Christoph Strobl - * @author Mark Paluch - * @deprecated since 2.0, use pooling via {@link LettucePoolingClientConfiguration}. - */ -@Deprecated -public interface LettucePool extends Pool> { - - /** - * @return The {@link AbstractRedisClient} used to create pooled connections - */ - @Nullable - AbstractRedisClient getClient(); - -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java index 59073020f0..c4bf04f071 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java @@ -229,7 +229,7 @@ Function translateException() { if (throwable instanceof RuntimeException) { - DataAccessException convertedException = LettuceConverters.exceptionConverter() + DataAccessException convertedException = LettuceExceptionConverter.INSTANCE .convert((RuntimeException) throwable); return convertedException != null ? convertedException : throwable; } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java index 39a534ad89..85cdb59a9c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java @@ -44,7 +44,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy( - LettuceConverters.exceptionConverter()); + LettuceExceptionConverter.INSTANCE); private final LettuceConnectionProvider provider; private StatefulRedisSentinelConnection connection; // no that should not be null diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java deleted file mode 100644 index d61b278cb2..0000000000 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/AuthenticatingRedisClientTests.java +++ /dev/null @@ -1,110 +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.lettuce; - -import io.lettuce.core.RedisClient; -import io.lettuce.core.RedisException; -import io.lettuce.core.api.StatefulRedisConnection; -import io.lettuce.core.pubsub.StatefulRedisPubSubConnection; - -import java.util.concurrent.TimeUnit; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.data.redis.test.condition.EnabledOnRedisAvailable; - -/** - * Integration test of {@link AuthenticatingRedisClient}. - * - * @author Jennifer Hickey - * @author Thomas Darimont - * @author Christoph Strobl - */ -@EnabledOnRedisAvailable(6382) -class AuthenticatingRedisClientTests { - - private RedisClient client; - - @BeforeEach - void setUp() { - client = new AuthenticatingRedisClient("localhost", 6382, "foobared"); - } - - @AfterEach - void tearDown() { - if (client != null) { - client.shutdown(); - } - } - - @Test - void connect() { - StatefulRedisConnection conn = client.connect(); - conn.sync().ping(); - conn.close(); - } - - @Test - void connectWithInvalidPassword() { - - if (client != null) { - client.shutdown(); - } - - RedisClient badClient = new AuthenticatingRedisClient("localhost", 6382, "notthepassword"); - Assertions.assertThatExceptionOfType(RedisException.class).isThrownBy(badClient::connect); - badClient.shutdown(0, 0, TimeUnit.MILLISECONDS); - } - - @Test - void codecConnect() { - StatefulRedisConnection conn = client.connect(LettuceConnection.CODEC); - conn.sync().ping(); - conn.close(); - } - - @Test - void connectAsync() { - StatefulRedisConnection conn = client.connect(); - conn.sync().ping(); - conn.close(); - } - - @Test - void codecConnectAsync() { - StatefulRedisConnection conn = client.connect(LettuceConnection.CODEC); - conn.sync().ping(); - conn.close(); - } - - @Test - void connectPubSub() { - StatefulRedisPubSubConnection conn = client.connectPubSub(); - conn.sync().ping(); - conn.close(); - } - - @Test - void codecConnectPubSub() { - StatefulRedisPubSubConnection conn = client.connectPubSub(LettuceConnection.CODEC); - conn.sync().ping(); - conn.close(); - } - -} diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java deleted file mode 100644 index 0b087aeb11..0000000000 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java +++ /dev/null @@ -1,195 +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.lettuce; - -import static org.assertj.core.api.Assertions.*; -import static org.springframework.test.util.ReflectionTestUtils.*; - -import io.lettuce.core.RedisException; -import io.lettuce.core.RedisURI; -import io.lettuce.core.api.StatefulRedisConnection; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import org.springframework.data.redis.SettingsUtils; -import org.springframework.data.redis.connection.PoolException; -import org.springframework.data.redis.connection.RedisSentinelConfiguration; -import org.springframework.data.redis.test.extension.LettuceTestClientResources; - -/** - * Unit test of {@link DefaultLettucePool} - * - * @author Jennifer Hickey - * @author Thomas Darimont - * @author Christoph Strobl - * @author Mark Paluch - */ -class DefaultLettucePoolTests { - - private DefaultLettucePool pool; - - @AfterEach - void tearDown() { - - if (pool != null) { - - if (pool.getClient() != null) { - pool.getClient().shutdown(0, 0, TimeUnit.MILLISECONDS); - } - - pool.destroy(); - } - } - - @Test - void testGetResource() { - - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - StatefulRedisConnection client = (StatefulRedisConnection) pool.getResource(); - assertThat(client).isNotNull(); - client.sync().ping(); - client.close(); - } - - @Test - void testGetResourcePoolExhausted() { - - GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); - poolConfig.setMaxTotal(1); - poolConfig.setMaxWaitMillis(1); - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - StatefulRedisConnection client = (StatefulRedisConnection) pool.getResource(); - assertThat(client).isNotNull(); - try { - pool.getResource(); - fail("PoolException should be thrown when pool exhausted"); - } catch (PoolException e) {} finally { - client.close(); - } - } - - @Test - void testGetResourceValidate() { - - GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); - poolConfig.setTestOnBorrow(true); - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - StatefulRedisConnection client = (StatefulRedisConnection) pool.getResource(); - assertThat(client).isNotNull(); - client.close(); - } - - @Test - void testGetResourceCreationUnsuccessful() throws Exception { - - pool = new DefaultLettucePool(SettingsUtils.getHost(), 3333); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - assertThatExceptionOfType(PoolException.class).isThrownBy(() -> pool.getResource()); - } - - @Test - void testReturnResource() { - - GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); - poolConfig.setMaxTotal(1); - poolConfig.setMaxWaitMillis(1); - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - StatefulRedisConnection client = (StatefulRedisConnection) pool.getResource(); - assertThat(client).isNotNull(); - pool.returnResource(client); - assertThat(pool.getResource()).isNotNull(); - client.close(); - } - - @Test - void testReturnBrokenResource() { - - GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); - poolConfig.setMaxTotal(1); - poolConfig.setMaxWaitMillis(1); - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - StatefulRedisConnection client = (StatefulRedisConnection) pool.getResource(); - assertThat(client).isNotNull(); - pool.returnBrokenResource(client); - StatefulRedisConnection client2 = (StatefulRedisConnection) pool.getResource(); - assertThat(client2).isNotSameAs(client); - try { - client.sync().ping(); - fail("Broken resouce connection should be closed"); - } catch (RedisException e) {} finally { - client.close(); - client2.close(); - } - } - - @Test - void testCreateWithDbIndex() { - - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.setDatabase(1); - pool.afterPropertiesSet(); - assertThat(pool.getResource()).isNotNull(); - } - - @Test - void testCreateWithDbIndexInvalid() { - - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.setDatabase(17); - pool.afterPropertiesSet(); - assertThatExceptionOfType(PoolException.class).isThrownBy(() -> pool.getResource()); - } - - @Test // DATAREDIS-524 - void testCreateSentinelWithPassword() { - - pool = new DefaultLettucePool(new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234"))); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.setPassword("foo"); - pool.afterPropertiesSet(); - - RedisURI redisUri = (RedisURI) getField(pool.getClient(), "redisURI"); - - assertThat(redisUri.getPassword()).isEqualTo(pool.getPassword().toCharArray()); - } - - @Test // DATAREDIS-462 - void poolWorksWithoutClientResources() { - - pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setDatabase(1); - pool.afterPropertiesSet(); - assertThat(pool.getResource()).isNotNull(); - } -} diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java index 530aa4ceca..77f328ffef 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java @@ -300,23 +300,6 @@ void testGetSharedConnectionNotShared() { assertThat(factory.getSharedConnection()).isNull(); } - @Test - void testCreateFactoryWithPool() { - DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool); - factory2.setShutdownTimeout(0); - factory2.afterPropertiesSet(); - - ConnectionFactoryTracker.add(factory2); - - RedisConnection conn2 = factory2.getConnection(); - conn2.close(); - factory2.destroy(); - pool.destroy(); - } - @Test // DATAREDIS-431 void dbIndexShouldBePropagatedCorrectly() { 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 d36536a7ab..f1c90e671a 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 @@ -17,13 +17,10 @@ import static org.assertj.core.api.Assertions.*; -import io.lettuce.core.api.async.RedisAsyncCommands; - import java.util.Arrays; import java.util.List; import java.util.Set; -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -121,48 +118,6 @@ void testCloseBlockingOps() { } catch (RedisSystemException e) {} } - @Test - void testClosePooledConnectionWithShared() { - DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool); - factory2.setShutdownTimeout(0); - factory2.afterPropertiesSet(); - RedisConnection connection = factory2.getConnection(); - // Use the connection to make sure the channel is initialized, else nothing happens on close - connection.ping(); - connection.close(); - // The shared connection should not be closed - connection.ping(); - - // The dedicated connection should not be closed b/c it's part of a pool - connection.multi(); - connection.close(); - factory2.destroy(); - pool.destroy(); - } - - @Test - void testClosePooledConnectionNotShared() { - DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool); - factory2.setShareNativeConnection(false); - factory2.afterPropertiesSet(); - RedisConnection connection = factory2.getConnection(); - // Use the connection to make sure the channel is initialized, else nothing happens on close - connection.ping(); - connection.close(); - // The dedicated connection should not be closed - connection.ping(); - - connection.close(); - factory2.destroy(); - pool.destroy(); - } - @Test void testCloseNonPooledConnectionNotShared() { LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(), SettingsUtils.getPort()); @@ -182,60 +137,6 @@ void testCloseNonPooledConnectionNotShared() { factory2.destroy(); } - @SuppressWarnings("rawtypes") - @Test - void testCloseReturnBrokenResourceToPool() { - DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool); - factory2.setShutdownTimeout(0); - factory2.setShareNativeConnection(false); - factory2.afterPropertiesSet(); - RedisConnection connection = factory2.getConnection(); - // Use the connection to make sure the channel is initialized, else nothing happens on close - connection.ping(); - ((RedisAsyncCommands) connection.getNativeConnection()).getStatefulConnection().close(); - try { - connection.ping(); - fail("Exception should be thrown trying to use a closed connection"); - } catch (RedisSystemException e) {} - connection.close(); - factory2.destroy(); - pool.destroy(); - } - - @Test // DATAREDIS-1062 - void testSelectNotShared() { - DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort()); - GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - config.setMaxTotal(1); - config.setMaxIdle(1); - pool.setPoolConfig(config); - pool.setClientResources(LettuceTestClientResources.getSharedClientResources()); - pool.afterPropertiesSet(); - LettuceConnectionFactory factory2 = new LettuceConnectionFactory(pool); - factory2.setDatabase(0); - factory2.setShutdownTimeout(0); - factory2.setShareNativeConnection(false); - factory2.afterPropertiesSet(); - RedisConnection connection = factory2.getConnection(); - - connection.select(2); - connection.rPush("key".getBytes(), "value1".getBytes(), "value2".getBytes()); - List bytes = connection.bLPop(1, "key".getBytes()); - assertThat(bytes).hasSize(2); - connection.close(); - - connection = factory2.getConnection(); - assertThat(connection.lLen("key".getBytes())).isEqualTo(0); - connection.select(2); - assertThat(connection.lLen("key".getBytes())).isEqualTo(1); - - factory2.destroy(); - pool.destroy(); - } - @Test public void testSelect() { assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> super.testSelect()); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java index 41bd3fd2ac..37940512ef 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionUnitTests.java @@ -143,7 +143,7 @@ void shouldThrowExceptionWhenAccessingRedisSentinelsCommandsWhenNoSentinelsConfi @Test // DATAREDIS-431 void dbIndexShouldBeSetWhenObtainingConnection() { - connection = new LettuceConnection(null, 0, clientMock, null, 0); + connection = new LettuceConnection(null, 0, clientMock, 0); connection.select(1); connection.getNativeConnection(); @@ -156,7 +156,7 @@ void translatesUnknownExceptions() { IllegalArgumentException exception = new IllegalArgumentException("Aw, snap!"); when(syncCommandsMock.set(any(), any())).thenThrow(exception); - connection = new LettuceConnection(null, 0, clientMock, null, 1); + connection = new LettuceConnection(null, 0, clientMock, 1); assertThatThrownBy(() -> connection.set("foo".getBytes(), "bar".getBytes())) .hasMessageContaining(exception.getMessage()).hasRootCause(exception); @@ -168,7 +168,7 @@ void translatesPipelineUnknownExceptions() throws Exception { IllegalArgumentException exception = new IllegalArgumentException("Aw, snap!"); when(asyncCommandsMock.set(any(byte[].class), any(byte[].class))).thenThrow(exception); - connection = new LettuceConnection(null, 0, clientMock, null, 1); + connection = new LettuceConnection(null, 0, clientMock, 1); connection.openPipeline(); assertThatThrownBy(() -> connection.set("foo".getBytes(), "bar".getBytes())) From 7f8de6dbfdb2e4f66e437d35ac210753e183ea1f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 23 Feb 2022 10:30:32 +0100 Subject: [PATCH 04/12] Move Tuple, Limit, and Weights to top-level types. --- .../springframework/data/redis/Version.java | 103 -------- .../data/redis/VersionParser.java | 58 ----- .../DefaultStringRedisConnection.java | 35 ++- .../redis/connection/DefaultStringTuple.java | 3 +- .../connection/DefaultedRedisConnection.java | 22 +- .../data/redis/connection/Limit.java | 73 ++++++ .../connection/ReactiveStreamCommands.java | 1 - .../connection/ReactiveZSetCommands.java | 6 +- .../redis/connection/RedisStreamCommands.java | 1 - .../redis/connection/RedisZSetCommands.java | 239 ++---------------- .../connection/StringRedisConnection.java | 26 +- .../redis/connection/convert/Converters.java | 2 +- .../jedis/JedisClusterStreamCommands.java | 6 +- .../jedis/JedisClusterZSetCommands.java | 18 +- .../connection/jedis/JedisConverters.java | 4 +- .../connection/jedis/JedisStreamCommands.java | 6 +- .../redis/connection/jedis/JedisUtils.java | 4 +- .../connection/jedis/JedisZSetCommands.java | 18 +- .../connection/lettuce/LettuceConverters.java | 12 +- .../lettuce/LettuceReactiveZSetCommands.java | 6 +- .../lettuce/LettuceStreamCommands.java | 2 +- .../lettuce/LettuceZSetCommands.java | 16 +- .../connection/{ => zset}/DefaultTuple.java | 6 +- .../data/redis/connection/zset/Tuple.java | 43 ++++ .../data/redis/connection/zset/Weights.java | 165 ++++++++++++ .../data/redis/core/AbstractOperations.java | 4 +- .../redis/core/BoundStreamOperations.java | 2 +- .../data/redis/core/BoundZSetOperations.java | 6 +- .../core/DefaultBoundStreamOperations.java | 2 +- .../core/DefaultBoundZSetOperations.java | 4 +- .../core/DefaultReactiveStreamOperations.java | 2 +- .../core/DefaultReactiveZSetOperations.java | 9 +- .../redis/core/DefaultStreamOperations.java | 2 +- .../redis/core/DefaultZSetOperations.java | 6 +- .../redis/core/ReactiveStreamOperations.java | 16 +- .../redis/core/ReactiveZSetOperations.java | 6 +- .../data/redis/core/RedisTemplate.java | 2 +- .../data/redis/core/StreamOperations.java | 15 +- .../data/redis/core/ZSetOperations.java | 6 +- .../support/collections/DefaultRedisZSet.java | 2 +- .../redis/support/collections/RedisZSet.java | 15 +- .../ReactiveStreamOperationsExtensions.kt | 2 +- .../core/ReactiveZSetOperationsExtensions.kt | 25 +- .../data/redis/VersionParserUnitTests.java | 56 ---- .../AbstractConnectionIntegrationTests.java | 4 +- .../DefaultStringRedisConnectionTests.java | 6 +- .../connection/RedisConnectionUnitTests.java | 15 +- .../redis/connection/WeightsUnitTests.java | 8 +- .../jedis/JedisClusterConnectionTests.java | 4 +- .../jedis/JedisConnectionUnitTests.java | 2 +- .../LettuceClusterConnectionTests.java | 3 + .../lettuce/LettuceConvertersUnitTests.java | 7 +- ...eactiveStreamCommandsIntegrationTests.java | 2 +- ...eReactiveZSetCommandsIntegrationTests.java | 2 +- ...ctiveStreamOperationsIntegrationTests.java | 2 +- ...eactiveZSetOperationsIntegrationTests.java | 4 +- ...faultStreamOperationsIntegrationTests.java | 2 +- ...DefaultZSetOperationsIntegrationTests.java | 9 +- .../AbstractRedisZSetTestIntegration.java | 7 +- ...tiveStreamOperationsExtensionsUnitTests.kt | 2 +- ...activeZSetOperationsExtensionsUnitTests.kt | 18 +- 61 files changed, 525 insertions(+), 629 deletions(-) delete mode 100644 src/main/java/org/springframework/data/redis/Version.java delete mode 100644 src/main/java/org/springframework/data/redis/VersionParser.java create mode 100644 src/main/java/org/springframework/data/redis/connection/Limit.java rename src/main/java/org/springframework/data/redis/connection/{ => zset}/DefaultTuple.java (92%) create mode 100644 src/main/java/org/springframework/data/redis/connection/zset/Tuple.java create mode 100644 src/main/java/org/springframework/data/redis/connection/zset/Weights.java delete mode 100644 src/test/java/org/springframework/data/redis/VersionParserUnitTests.java diff --git a/src/main/java/org/springframework/data/redis/Version.java b/src/main/java/org/springframework/data/redis/Version.java deleted file mode 100644 index 8bac1c9e24..0000000000 --- a/src/main/java/org/springframework/data/redis/Version.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2011-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; - -/** - * A {@link Comparable} software version - * - * @author Jennifer Hickey - * @author Christoph Strobl - * @deprecated since 2.0, use {@link org.springframework.data.util.Version}. - */ -public class Version implements Comparable { - - public static final Version UNKNOWN = new Version(0, 0, 0); - - Integer major; - Integer minor; - Integer patch; - - public Version(int major, int minor, int patch) { - this.major = major; - this.minor = minor; - this.patch = patch; - } - - public int compareTo(Version o) { - if (this.major != o.major) { - return this.major.compareTo(o.major); - } - if (this.minor != o.minor) { - return this.minor.compareTo(o.minor); - } - if (this.patch != o.patch) { - return this.patch.compareTo(o.patch); - } - return 0; - } - - @Override - public String toString() { - return "" + major + "." + minor + "." + patch; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((major == null) ? 0 : major.hashCode()); - result = prime * result + ((minor == null) ? 0 : minor.hashCode()); - result = prime * result + ((patch == null) ? 0 : patch.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof Version)) { - return false; - } - Version other = (Version) obj; - if (major == null) { - if (other.major != null) { - return false; - } - } else if (!major.equals(other.major)) { - return false; - } - if (minor == null) { - if (other.minor != null) { - return false; - } - } else if (!minor.equals(other.minor)) { - return false; - } - if (patch == null) { - if (other.patch != null) { - return false; - } - } else if (!patch.equals(other.patch)) { - return false; - } - return true; - } - -} diff --git a/src/main/java/org/springframework/data/redis/VersionParser.java b/src/main/java/org/springframework/data/redis/VersionParser.java deleted file mode 100644 index 963935f22e..0000000000 --- a/src/main/java/org/springframework/data/redis/VersionParser.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014-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; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.springframework.lang.Nullable; - -/** - * Central class for reading version string (eg. {@literal 1.3.1}) into {@link Version}. - * - * @author Christoph Strobl - * @since 1.3 - * @deprecated since 2.0, use {@link org.springframework.data.util.Version}. - */ -public class VersionParser { - - private static final Pattern VERSION_MATCHER = Pattern.compile("([0-9]+)\\.([0-9]+)(\\.([0-9]+))?(.*)"); - - /** - * Parse version string {@literal eg. 1.1.1} to {@link Version}. - * - * @param version can be {@literal null}. - * @return never {@literal null}. - */ - public static Version parseVersion(@Nullable String version) { - - if (version == null) { - return Version.UNKNOWN; - } - - Matcher matcher = VERSION_MATCHER.matcher(version); - if (matcher.matches()) { - String major = matcher.group(1); - String minor = matcher.group(2); - String patch = matcher.group(4); - return new Version(Integer.parseInt(major), minor != null ? Integer.parseInt(minor) : 0, - patch != null ? Integer.parseInt(patch) : 0); - } - - return Version.UNKNOWN; - } - -} diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 0892dace34..500b1a2b61 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -48,6 +48,9 @@ import org.springframework.data.redis.connection.stream.StreamOffset; import org.springframework.data.redis.connection.stream.StreamReadOptions; import org.springframework.data.redis.connection.stream.StringRecord; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ConvertingCursor; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; @@ -1031,7 +1034,7 @@ public Set zRangeByScore(byte[] key, Range range) { } @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRangeByScore(key, range, limit), Converters.identityConverter()); } @@ -1052,7 +1055,8 @@ public Set zRangeByScoreWithScores(byte[] key, double min, double max, lo } @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRangeByScoreWithScores(key, range, limit), Converters.identityConverter()); } @@ -1082,7 +1086,7 @@ public Set zRevRangeByScore(byte[] key, double min, double max) { } @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRevRangeByScore(key, range, limit), Converters.identityConverter()); } @@ -1098,7 +1102,8 @@ public Set zRevRangeByScoreWithScores(byte[] key, Range range) { } @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRevRangeByScoreWithScores(key, range, limit), Converters.identityConverter()); } @@ -2578,7 +2583,7 @@ public Set zRangeByLex(byte[] key, Range range) { } @Override - public Set zRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRangeByLex(key, range, limit), Converters.identityConverter()); } @@ -2589,21 +2594,21 @@ public Set zRangeByLex(String key) { @Override public Set zRangeByLex(String key, Range range) { - return zRangeByLex(key, range, Limit.unlimited()); + return zRangeByLex(key, range, org.springframework.data.redis.connection.Limit.unlimited()); } @Override - public Set zRangeByLex(String key, Range range, Limit limit) { + public Set zRangeByLex(String key, Range range, org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRangeByLex(serialize(key), range, limit), byteSetToStringSet); } @Override - public Set zRevRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRevRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRevRangeByLex(key, range, limit), Converters.identityConverter()); } @Override - public Set zRevRangeByLex(String key, Range range, Limit limit) { + public Set zRevRangeByLex(String key, Range range, org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.zRevRangeByLex(serialize(key), range, limit), byteSetToStringSet); } @@ -2709,7 +2714,8 @@ public PendingMessages xPending(String key, String groupName, XPendingOptions op } @Override - public List xRange(String key, org.springframework.data.domain.Range range, Limit limit) { + public List xRange(String key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.xRange(serialize(key), range, limit), listByteMapRecordToStringMapRecordConverter); } @@ -2728,7 +2734,8 @@ public List xReadGroupAsString(Consumer consumer, StreamReadOption } @Override - public List xRevRange(String key, org.springframework.data.domain.Range range, Limit limit) { + public List xRevRange(String key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit) { return convertAndReturn(delegate.xRevRange(serialize(key), range, limit), listByteMapRecordToStringMapRecordConverter); @@ -2820,7 +2827,8 @@ public PendingMessages xPending(byte[] key, String groupName, XPendingOptions op } @Override - public List xRange(byte[] key, org.springframework.data.domain.Range range, Limit limit) { + public List xRange(byte[] key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit) { return delegate.xRange(key, range, limit); } @@ -2836,7 +2844,8 @@ public List xReadGroup(Consumer consumer, StreamReadOptions readOpti } @Override - public List xRevRange(byte[] key, org.springframework.data.domain.Range range, Limit limit) { + public List xRevRange(byte[] key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit) { return delegate.xRevRange(key, range, limit); } diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringTuple.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringTuple.java index f681d992ea..6735c21ff7 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringTuple.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringTuple.java @@ -17,8 +17,9 @@ import java.nio.charset.StandardCharsets; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.util.ObjectUtils; /** diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java index 2f846fc508..773d37d8c5 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -40,6 +40,8 @@ import org.springframework.data.redis.connection.stream.StreamInfo.XInfoStream; import org.springframework.data.redis.connection.stream.StreamOffset; import org.springframework.data.redis.connection.stream.StreamReadOptions; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.types.Expiration; @@ -584,7 +586,8 @@ default List xRange(byte[] key, org.springframework.data.domain.Rang /** @deprecated in favor of {@link RedisConnection#streamCommands()}}. */ @Override @Deprecated - default List xRange(byte[] key, org.springframework.data.domain.Range range, Limit limit) { + default List xRange(byte[] key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit) { return streamCommands().xRange(key, range, limit); } @@ -627,7 +630,8 @@ default List xRevRange(byte[] key, org.springframework.data.domain.R /** @deprecated in favor of {@link RedisConnection#streamCommands()}}. */ @Override @Deprecated - default List xRevRange(byte[] key, org.springframework.data.domain.Range range, Limit limit) { + default List xRevRange(byte[] key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit) { return streamCommands().xRevRange(key, range, limit); } @@ -1136,28 +1140,29 @@ default Set zRangeWithScores(byte[] key, long start, long end) { /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ @Override @Deprecated - default Set zRangeByLex(byte[] key, Range range, Limit limit) { + default Set zRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return zSetCommands().zRangeByLex(key, range, limit); } /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ @Override @Deprecated - default Set zRevRangeByLex(byte[] key, Range range, Limit limit) { + default Set zRevRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return zSetCommands().zRevRangeByLex(key, range, limit); } /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ @Override @Deprecated - default Set zRangeByScore(byte[] key, Range range, Limit limit) { + default Set zRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return zSetCommands().zRangeByScore(key, range, limit); } /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ @Override @Deprecated - default Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + default Set zRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { return zSetCommands().zRangeByScoreWithScores(key, range, limit); } @@ -1171,14 +1176,15 @@ default Set zRevRangeWithScores(byte[] key, long start, long end) { /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ @Override @Deprecated - default Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + default Set zRevRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return zSetCommands().zRevRangeByScore(key, range, limit); } /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ @Override @Deprecated - default Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + default Set zRevRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { return zSetCommands().zRevRangeByScoreWithScores(key, range, limit); } diff --git a/src/main/java/org/springframework/data/redis/connection/Limit.java b/src/main/java/org/springframework/data/redis/connection/Limit.java new file mode 100644 index 0000000000..7e8a6b8662 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/Limit.java @@ -0,0 +1,73 @@ +/* + * Copyright 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; + +/** + * @author Christoph Strobl + * @since 1.6 + */ +public class Limit { + + private static final Limit UNLIMITED = new Limit() { + + @Override + public int getCount() { + return -1; + } + + @Override + public int getOffset() { + return super.getOffset(); + } + }; + + int offset; + int count; + + public static Limit limit() { + return new Limit(); + } + + public Limit offset(int offset) { + this.offset = offset; + return this; + } + + public Limit count(int count) { + this.count = count; + return this; + } + + public int getCount() { + return count; + } + + public int getOffset() { + return offset; + } + + public boolean isUnlimited() { + return this.equals(UNLIMITED); + } + + /** + * @return new {@link Limit} indicating no limit; + * @since 1.3 + */ + public static Limit unlimited() { + return UNLIMITED; + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java index f4332bef9e..522cce5dd3 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveStreamCommands.java @@ -33,7 +33,6 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; import org.springframework.data.redis.connection.RedisStreamCommands.XClaimOptions; import org.springframework.data.redis.connection.RedisStreamCommands.XPendingOptions; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.stream.ByteBufferRecord; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.PendingMessage; diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java index f8fe28d256..0b7de03e13 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java @@ -34,9 +34,9 @@ import org.springframework.data.domain.Range; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.util.ByteUtils; import org.springframework.lang.Nullable; diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java index ab95503680..d6333067c0 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStreamCommands.java @@ -24,7 +24,6 @@ import java.util.stream.Collectors; import org.springframework.data.domain.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.stream.*; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoConsumers; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoGroups; diff --git a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java index 161913c33a..a85be1de79 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java @@ -15,18 +15,13 @@ */ package org.springframework.data.redis.connection; -import java.util.Arrays; -import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.function.DoubleUnaryOperator; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.lang.Nullable; @@ -52,160 +47,6 @@ enum Aggregate { SUM, MIN, MAX; } - /** - * Value object encapsulating a multiplication factor for each input sorted set. This means that the score of every - * element in every input sorted set is multiplied by this factor before being passed to the aggregation function. - * - * @author Mark Paluch - * @author Christoph Strobl - * @since 2.1 - */ - class Weights { - - private final List weights; - - private Weights(List weights) { - this.weights = weights; - } - - /** - * Create new {@link Weights} given {@code weights} as {@code int}. - * - * @param weights must not be {@literal null}. - * @return the {@link Weights} for {@code weights}. - */ - public static Weights of(int... weights) { - - Assert.notNull(weights, "Weights must not be null!"); - return new Weights(Arrays.stream(weights).mapToDouble(value -> value).boxed().collect(Collectors.toList())); - } - - /** - * Create new {@link Weights} given {@code weights} as {@code double}. - * - * @param weights must not be {@literal null}. - * @return the {@link Weights} for {@code weights}. - */ - public static Weights of(double... weights) { - - Assert.notNull(weights, "Weights must not be null!"); - - return new Weights(DoubleStream.of(weights).boxed().collect(Collectors.toList())); - } - - /** - * Creates equal {@link Weights} for a number of input sets {@code count} with a weight of one. - * - * @param count number of input sets. Must be greater or equal to zero. - * @return equal {@link Weights} for a number of input sets with a weight of one. - */ - public static Weights fromSetCount(int count) { - - Assert.isTrue(count >= 0, "Count of input sorted sets must be greater or equal to zero!"); - - return new Weights(IntStream.range(0, count).mapToDouble(value -> 1).boxed().collect(Collectors.toList())); - } - - /** - * Creates a new {@link Weights} object that contains all weights multiplied by {@code multiplier} - * - * @param multiplier multiplier used to multiply each weight with. - * @return equal {@link Weights} for a number of input sets with a weight of one. - */ - public Weights multiply(int multiplier) { - return apply(it -> it * multiplier); - } - - /** - * Creates a new {@link Weights} object that contains all weights multiplied by {@code multiplier} - * - * @param multiplier multiplier used to multiply each weight with. - * @return equal {@link Weights} for a number of input sets with a weight of one. - */ - public Weights multiply(double multiplier) { - return apply(it -> it * multiplier); - } - - /** - * Creates a new {@link Weights} object that contains all weights with {@link Function} applied. - * - * @param operator operator function. - * @return the new {@link Weights} with {@link DoubleUnaryOperator} applied. - */ - public Weights apply(Function operator) { - return new Weights(weights.stream().map(operator).collect(Collectors.toList())); - } - - /** - * Retrieve the weight at {@code index}. - * - * @param index the weight index. - * @return the weight at {@code index}. - * @throws IndexOutOfBoundsException if the index is out of range - */ - public double getWeight(int index) { - return weights.get(index); - } - - /** - * @return number of weights. - */ - public int size() { - return weights.size(); - } - - /** - * @return an array containing all of the weights in this list in proper sequence (from first to last element). - */ - public double[] toArray() { - return weights.stream().mapToDouble(Double::doubleValue).toArray(); - } - - /** - * @return a {@link List} containing all of the weights in this list in proper sequence (from first to last - * element). - */ - public List toList() { - return Collections.unmodifiableList(weights); - } - - @Override - public boolean equals(Object o) { - - if (this == o) { - return true; - } - - if (!(o instanceof Weights)) { - return false; - } - - Weights that = (Weights) o; - return ObjectUtils.nullSafeEquals(this.weights, that.weights); - } - - @Override - public int hashCode() { - return ObjectUtils.nullSafeHashCode(weights); - } - } - - /** - * ZSet tuple. - */ - interface Tuple extends Comparable { - - /** - * @return the raw value of the member. - */ - byte[] getValue(); - - /** - * @return the member score value used for sorting. - */ - Double getScore(); - } - /** * {@link Range} defines {@literal min} and {@literal max} values to retrieve from a {@literal ZSET}. * @@ -336,58 +177,11 @@ public boolean isIncluding() { /** * @author Christoph Strobl * @since 1.6 + * @deprecated since 3.0, use {@link org.springframework.data.redis.connection.Limit} instead. */ - class Limit { - - private static final Limit UNLIMITED = new Limit() { - - @Override - public int getCount() { - return -1; - } - - @Override - public int getOffset() { - return super.getOffset(); - } - }; - - int offset; - int count; - - public static Limit limit() { - return new Limit(); - } - - public Limit offset(int offset) { - this.offset = offset; - return this; - } - - public Limit count(int count) { - this.count = count; - return this; - } - - public int getCount() { - return count; - } - - public int getOffset() { - return offset; - } - - public boolean isUnlimited() { - return this.equals(UNLIMITED); - } + @Deprecated + class Limit extends org.springframework.data.redis.connection.Limit { - /** - * @return new {@link Limit} indicating no limit; - * @since 1.3 - */ - public static Limit unlimited() { - return UNLIMITED; - } } /** @@ -787,7 +581,8 @@ default Set zRangeByScoreWithScores(byte[] key, double min, double max) { @Nullable default Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { return zRangeByScore(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + new org.springframework.data.redis.connection.Limit().offset(Long.valueOf(offset).intValue()) + .count(Long.valueOf(count).intValue())); } /** @@ -806,7 +601,8 @@ default Set zRangeByScore(byte[] key, double min, double max, long offse @Nullable default Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + new org.springframework.data.redis.connection.Limit().offset(Long.valueOf(offset).intValue()) + .count(Long.valueOf(count).intValue())); } /** @@ -822,7 +618,7 @@ default Set zRangeByScoreWithScores(byte[] key, double min, double max, l * @see Redis Documentation: ZRANGEBYSCORE */ @Nullable - Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit); + Set zRangeByScoreWithScores(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit); /** * Get elements in range from {@code start} to {@code end} from sorted set ordered from high to low. @@ -928,7 +724,7 @@ default Set zRevRangeByScore(byte[] key, double min, double max, long of * @see Redis Documentation: ZREVRANGEBYSCORE */ @Nullable - Set zRevRangeByScore(byte[] key, Range range, Limit limit); + Set zRevRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit); /** * Get set of {@link Tuple} in range from {@code start} to {@code end} where score is between {@code min} and @@ -946,7 +742,8 @@ default Set zRevRangeByScore(byte[] key, double min, double max, long of default Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + new org.springframework.data.redis.connection.Limit().offset(Long.valueOf(offset).intValue()) + .count(Long.valueOf(count).intValue())); } /** @@ -976,7 +773,7 @@ default Set zRevRangeByScoreWithScores(byte[] key, Range range) { * @see Redis Documentation: ZREVRANGEBYSCORE */ @Nullable - Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit); + Set zRevRangeByScoreWithScores(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit); /** * Count number of elements within sorted set with scores between {@code min} and {@code max}. @@ -1454,7 +1251,7 @@ default Set zRangeByScore(byte[] key, Range range) { * @see Redis Documentation: ZRANGEBYSCORE */ @Nullable - Set zRangeByScore(byte[] key, Range range, Limit limit); + Set zRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit); /** * Get all the elements in the sorted set at {@literal key} in lexicographical ordering. @@ -1495,7 +1292,7 @@ default Set zRangeByLex(byte[] key, Range range) { * @see Redis Documentation: ZRANGEBYLEX */ @Nullable - Set zRangeByLex(byte[] key, Range range, Limit limit); + Set zRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit); /** * Get all the elements in the sorted set at {@literal key} in reversed lexicographical ordering. @@ -1521,7 +1318,7 @@ default Set zRevRangeByLex(byte[] key) { */ @Nullable default Set zRevRangeByLex(byte[] key, Range range) { - return zRevRangeByLex(key, range, Limit.unlimited()); + return zRevRangeByLex(key, range, org.springframework.data.redis.connection.Limit.unlimited()); } /** @@ -1536,6 +1333,6 @@ default Set zRevRangeByLex(byte[] key, Range range) { * @see Redis Documentation: ZREVRANGEBYLEX */ @Nullable - Set zRevRangeByLex(byte[] key, Range range, Limit limit); + Set zRevRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit); } diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java index 3a917d83dd..8a71eed037 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -41,6 +41,8 @@ import org.springframework.data.redis.connection.stream.StreamReadOptions; import org.springframework.data.redis.connection.stream.StreamRecords; import org.springframework.data.redis.connection.stream.StringRecord; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.ScanOptions; @@ -1929,7 +1931,7 @@ default Set zUnionWithScores(Aggregate aggregate, int[] weights, St /** * Get all the elements in {@link Range} from the sorted set at {@literal key} in lexicographical ordering. Result is - * limited via {@link Limit}. + * limited via {@link org.springframework.data.redis.connection.Limit}. * * @param key must not be {@literal null}. * @param range must not be {@literal null}. @@ -1939,7 +1941,7 @@ default Set zUnionWithScores(Aggregate aggregate, int[] weights, St * @see Redis Documentation: ZRANGEBYLEX * @see RedisZSetCommands#zRangeByLex(byte[], Range, Limit) */ - Set zRangeByLex(String key, Range range, Limit limit); + Set zRangeByLex(String key, Range range, org.springframework.data.redis.connection.Limit limit); /** * Get all the elements in the sorted set at {@literal key} in reversed lexicographical ordering. @@ -1965,12 +1967,12 @@ default Set zRevRangeByLex(String key) { * @see RedisZSetCommands#zRevRangeByLex(byte[], Range) */ default Set zRevRangeByLex(String key, Range range) { - return zRevRangeByLex(key, range, Limit.unlimited()); + return zRevRangeByLex(key, range, org.springframework.data.redis.connection.Limit.unlimited()); } /** * Get all the elements in {@link Range} from the sorted set at {@literal key} in reversed lexicographical ordering. - * Result is limited via {@link Limit}. + * Result is limited via {@link org.springframework.data.redis.connection.Limit}. * * @param key must not be {@literal null}. * @param range must not be {@literal null}. @@ -1980,7 +1982,7 @@ default Set zRevRangeByLex(String key, Range range) { * @see Redis Documentation: ZREVRANGEBYLEX * @see RedisZSetCommands#zRevRangeByLex(byte[], Range, Limit) */ - Set zRevRangeByLex(String key, Range range, Limit limit); + Set zRevRangeByLex(String key, Range range, org.springframework.data.redis.connection.Limit limit); // ------------------------------------------------------------------------- // Methods dealing with Redis Hashes @@ -2866,11 +2868,12 @@ PendingMessages xPending(String key, String groupName, org.springframework.data. */ @Nullable default List xRange(String key, org.springframework.data.domain.Range range) { - return xRange(key, range, Limit.unlimited()); + return xRange(key, range, org.springframework.data.redis.connection.Limit.unlimited()); } /** - * Read records from a stream within a specific {@link Range} applying a {@link Limit}. + * Read records from a stream within a specific {@link Range} applying a + * {@link org.springframework.data.redis.connection.Limit}. * * @param key the stream key. * @param range must not be {@literal null}. @@ -2880,7 +2883,8 @@ default List xRange(String key, org.springframework.data.domain.Ra * @see Redis Documentation: XRANGE */ @Nullable - List xRange(String key, org.springframework.data.domain.Range range, Limit limit); + List xRange(String key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit); /** * Read records from one or more {@link StreamOffset}s. @@ -3007,7 +3011,8 @@ default List xRevRange(String key, org.springframework.data.domain } /** - * Read records from a stream within a specific {@link Range} applying a {@link Limit} in reverse order. + * Read records from a stream within a specific {@link Range} applying a + * {@link org.springframework.data.redis.connection.Limit} in reverse order. * * @param key the stream key. * @param range must not be {@literal null}. @@ -3017,7 +3022,8 @@ default List xRevRange(String key, org.springframework.data.domain * @see Redis Documentation: XREVRANGE */ @Nullable - List xRevRange(String key, org.springframework.data.domain.Range range, Limit limit); + List xRevRange(String key, org.springframework.data.domain.Range range, + org.springframework.data.redis.connection.Limit limit); /** * Trims the stream to {@code count} elements. 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 d3a9f27d7c..10ac7fd7a7 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 @@ -39,7 +39,7 @@ import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisNode.NodeType; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.util.ByteUtils; import org.springframework.lang.Nullable; 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 4f939de40a..294fc2e8b5 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 @@ -25,8 +25,8 @@ import org.springframework.dao.DataAccessException; 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.RedisZSetCommands; import org.springframework.data.redis.connection.stream.ByteRecord; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; @@ -226,7 +226,7 @@ public PendingMessages xPending(byte[] key, String groupName, XPendingOptions op } @Override - public List xRange(byte[] key, Range range, RedisZSetCommands.Limit limit) { + public List xRange(byte[] key, Range range, Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); @@ -292,7 +292,7 @@ public List xReadGroup(Consumer consumer, StreamReadOptions readOpti } @Override - public List xRevRange(byte[] key, Range range, RedisZSetCommands.Limit limit) { + public List xRevRange(byte[] key, Range range, Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); 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 6c7e208ac3..9e92134a1c 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 @@ -27,9 +27,11 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.ClusterSlotHashUtil; -import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.convert.SetConverter; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanCursor; import org.springframework.data.redis.core.ScanIteration; @@ -201,7 +203,8 @@ public Set zRange(byte[] key, long start, long end) { } @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); @@ -221,7 +224,7 @@ public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) } @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); @@ -240,7 +243,8 @@ public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { } @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); @@ -391,7 +395,7 @@ public Long zRemRangeByScore(byte[] key, Range range) { } @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); @@ -410,7 +414,7 @@ public Set zRangeByScore(byte[] key, Range range, Limit limit) { } @Override - public Set zRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null for ZRANGEBYLEX!"); @@ -446,7 +450,7 @@ public Long zRemRangeByLex(byte[] key, Range range) { } @Override - public Set zRevRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRevRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null for ZREVRANGEBYLEX!"); 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 bfd7b6d6fb..f915b49bd8 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 @@ -51,7 +51,6 @@ import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSet; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSubCommand; -import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; @@ -62,7 +61,6 @@ import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs; import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.SortParameters.Order; @@ -73,6 +71,8 @@ import org.springframework.data.redis.connection.convert.MapConverter; import org.springframework.data.redis.connection.convert.SetConverter; import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; 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 3bdc8512e1..49d32bbe38 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 @@ -28,8 +28,8 @@ import java.util.List; 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.RedisZSetCommands; import org.springframework.data.redis.connection.stream.ByteRecord; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; @@ -243,7 +243,7 @@ public PendingMessages xPending(byte[] key, String groupName, XPendingOptions op } @Override - public List xRange(byte[] key, Range range, RedisZSetCommands.Limit limit) { + public List xRange(byte[] key, Range range, Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); @@ -300,7 +300,7 @@ public List xReadGroup(Consumer consumer, StreamReadOptions readOpti } @Override - public List xRevRange(byte[] key, Range range, RedisZSetCommands.Limit limit) { + public List xRevRange(byte[] key, Range range, Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java index 3d5c9da2d9..f87c5cb576 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java @@ -41,14 +41,14 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.RedisConnectionFailureException; import org.springframework.data.redis.RedisSystemException; -import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisListCommands.Position; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.SortParameters.Range; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.util.Assert; /** 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 e9bf958dec..7a8d1960fb 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 @@ -28,8 +28,10 @@ import java.util.Set; import java.util.concurrent.TimeUnit; -import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisZSetCommands; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; @@ -171,7 +173,8 @@ public Set zRangeWithScores(byte[] key, long start, long end) { } @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); @@ -210,7 +213,7 @@ public Set zRevRangeWithScores(byte[] key, long start, long end) { } @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); @@ -229,7 +232,8 @@ public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { } @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); @@ -611,7 +615,7 @@ public Set zRangeByScore(byte[] key, String min, String max, long offset } @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); @@ -629,7 +633,7 @@ public Set zRangeByScore(byte[] key, Range range, Limit limit) { } @Override - public Set zRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZRANGEBYLEX must not be null!"); @@ -647,7 +651,7 @@ public Set zRangeByLex(byte[] key, Range range, Limit limit) { } @Override - public Set zRevRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRevRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYLEX must not be null!"); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 72ed8491ff..18325aa49a 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -40,6 +40,7 @@ import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSet; import org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldSubCommand; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisClusterNode.Flag; import org.springframework.data.redis.connection.RedisClusterNode.LinkState; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; @@ -48,11 +49,12 @@ import org.springframework.data.redis.connection.RedisNode.NodeType; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.convert.LongToBooleanConverter; import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.core.KeyScanOptions; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.types.Expiration; @@ -266,15 +268,15 @@ private static String boundaryToString(Boundary boundary, String inclPrefix, Str } /** - * Convert a {@link org.springframework.data.redis.connection.RedisZSetCommands.Limit} to a Lettuce - * {@link io.lettuce.core.Limit}. + * Convert a {@link Limit} to a Lettuce {@link io.lettuce.core.Limit}. * * @param limit * @return a lettuce {@link io.lettuce.core.Limit}. * @since 2.0 */ - public static io.lettuce.core.Limit toLimit(RedisZSetCommands.Limit limit) { - return limit.isUnlimited() ? Limit.unlimited() : Limit.create(limit.getOffset(), limit.getCount()); + public static io.lettuce.core.Limit toLimit(Limit limit) { + return limit.isUnlimited() ? io.lettuce.core.Limit.unlimited() + : io.lettuce.core.Limit.create(limit.getOffset(), limit.getCount()); } /** diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java index 5ab6f3c890..3bf31487f8 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java @@ -21,7 +21,6 @@ import io.lettuce.core.Value; import io.lettuce.core.ZAddArgs; import io.lettuce.core.ZStoreArgs; -import org.springframework.data.redis.core.TimeoutUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -32,7 +31,6 @@ import org.reactivestreams.Publisher; import org.springframework.data.domain.Sort.Direction; -import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyScanCommand; @@ -40,7 +38,9 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; import org.springframework.data.redis.connection.ReactiveZSetCommands; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.core.TimeoutUtils; import org.springframework.data.redis.util.ByteUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java index d25bc268be..7e3e0c15f1 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java @@ -28,8 +28,8 @@ import java.util.function.Function; 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.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.stream.ByteRecord; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; 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 332a0eaf9b..14614056b0 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 @@ -30,6 +30,8 @@ import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs.Flag; import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; @@ -161,7 +163,8 @@ public Set zRangeWithScores(byte[] key, long start, long end) { } @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); @@ -198,7 +201,7 @@ public Set zRevRangeWithScores(byte[] key, long start, long end) { } @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); @@ -217,7 +220,8 @@ public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { } @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); @@ -584,7 +588,7 @@ public Set zRangeByScore(byte[] key, String min, String max, long offset } @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); @@ -600,7 +604,7 @@ public Set zRangeByScore(byte[] key, Range range, Limit limit) { } @Override - public Set zRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZRANGEBYLEX must not be null!"); @@ -617,7 +621,7 @@ public Set zRangeByLex(byte[] key, Range range, Limit limit) { } @Override - public Set zRevRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRevRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYLEX must not be null!"); diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultTuple.java b/src/main/java/org/springframework/data/redis/connection/zset/DefaultTuple.java similarity index 92% rename from src/main/java/org/springframework/data/redis/connection/DefaultTuple.java rename to src/main/java/org/springframework/data/redis/connection/zset/DefaultTuple.java index 1a115571e0..42808c8905 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultTuple.java +++ b/src/main/java/org/springframework/data/redis/connection/zset/DefaultTuple.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2022 the original author or authors. + * Copyright 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. @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.redis.connection; +package org.springframework.data.redis.connection.zset; import java.util.Arrays; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; - /** * Default implementation for {@link Tuple} interface. * diff --git a/src/main/java/org/springframework/data/redis/connection/zset/Tuple.java b/src/main/java/org/springframework/data/redis/connection/zset/Tuple.java new file mode 100644 index 0000000000..d720351a02 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/zset/Tuple.java @@ -0,0 +1,43 @@ +/* + * Copyright 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.zset; + +/** + * ZSet tuple. + */ +public interface Tuple extends Comparable { + + /** + * @return the raw value of the member. + */ + byte[] getValue(); + + /** + * @return the member score value used for sorting. + */ + Double getScore(); + + /** + * Create a new {@link Tuple}. + * + * @param value + * @param score + * @return + */ + static Tuple of(byte[] value, Double score) { + return new DefaultTuple(value, score); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/zset/Weights.java b/src/main/java/org/springframework/data/redis/connection/zset/Weights.java new file mode 100644 index 0000000000..946aa7416a --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/zset/Weights.java @@ -0,0 +1,165 @@ +/* + * Copyright 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.zset; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.DoubleUnaryOperator; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; + +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +/** + * Value object encapsulating a multiplication factor for each input sorted set. This means that the score of every + * element in every input sorted set is multiplied by this factor before being passed to the aggregation function. + * + * @author Mark Paluch + * @author Christoph Strobl + * @since 2.1 + */ +public class Weights { + + private final List weights; + + private Weights(List weights) { + this.weights = weights; + } + + /** + * Create new {@link Weights} given {@code weights} as {@code int}. + * + * @param weights must not be {@literal null}. + * @return the {@link Weights} for {@code weights}. + */ + public static Weights of(int... weights) { + + Assert.notNull(weights, "Weights must not be null!"); + return new Weights(Arrays.stream(weights).mapToDouble(value -> value).boxed().collect(Collectors.toList())); + } + + /** + * Create new {@link Weights} given {@code weights} as {@code double}. + * + * @param weights must not be {@literal null}. + * @return the {@link Weights} for {@code weights}. + */ + public static Weights of(double... weights) { + + Assert.notNull(weights, "Weights must not be null!"); + + return new Weights(DoubleStream.of(weights).boxed().collect(Collectors.toList())); + } + + /** + * Creates equal {@link Weights} for a number of input sets {@code count} with a weight of one. + * + * @param count number of input sets. Must be greater or equal to zero. + * @return equal {@link Weights} for a number of input sets with a weight of one. + */ + public static Weights fromSetCount(int count) { + + Assert.isTrue(count >= 0, "Count of input sorted sets must be greater or equal to zero!"); + + return new Weights(IntStream.range(0, count).mapToDouble(value -> 1).boxed().collect(Collectors.toList())); + } + + /** + * Creates a new {@link Weights} object that contains all weights multiplied by {@code multiplier} + * + * @param multiplier multiplier used to multiply each weight with. + * @return equal {@link Weights} for a number of input sets with a weight of one. + */ + public Weights multiply(int multiplier) { + return apply(it -> it * multiplier); + } + + /** + * Creates a new {@link Weights} object that contains all weights multiplied by {@code multiplier} + * + * @param multiplier multiplier used to multiply each weight with. + * @return equal {@link Weights} for a number of input sets with a weight of one. + */ + public Weights multiply(double multiplier) { + return apply(it -> it * multiplier); + } + + /** + * Creates a new {@link Weights} object that contains all weights with {@link Function} applied. + * + * @param operator operator function. + * @return the new {@link Weights} with {@link DoubleUnaryOperator} applied. + */ + public Weights apply(Function operator) { + return new Weights(weights.stream().map(operator).collect(Collectors.toList())); + } + + /** + * Retrieve the weight at {@code index}. + * + * @param index the weight index. + * @return the weight at {@code index}. + * @throws IndexOutOfBoundsException if the index is out of range + */ + public double getWeight(int index) { + return weights.get(index); + } + + /** + * @return number of weights. + */ + public int size() { + return weights.size(); + } + + /** + * @return an array containing all of the weights in this list in proper sequence (from first to last element). + */ + public double[] toArray() { + return weights.stream().mapToDouble(Double::doubleValue).toArray(); + } + + /** + * @return a {@link List} containing all of the weights in this list in proper sequence (from first to last element). + */ + public List toList() { + return Collections.unmodifiableList(weights); + } + + @Override + public boolean equals(Object o) { + + if (this == o) { + return true; + } + + if (!(o instanceof Weights)) { + return false; + } + + Weights that = (Weights) o; + return ObjectUtils.nullSafeEquals(this.weights, that.weights); + } + + @Override + public int hashCode() { + return ObjectUtils.nullSafeHashCode(weights); + } +} diff --git a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java index 69842638d9..da6a56d0f8 100644 --- a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java +++ b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java @@ -25,11 +25,11 @@ import java.util.Set; import org.springframework.data.geo.GeoResults; -import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationUtils; diff --git a/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java b/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java index b591c95dd4..ac9265e124 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundStreamOperations.java @@ -19,7 +19,7 @@ import java.util.Map; import org.springframework.data.domain.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; import org.springframework.data.redis.connection.stream.ReadOffset; diff --git a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java index 8f883d68b5..819d0b4e17 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java @@ -22,11 +22,11 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.lang.Nullable; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java index c36741bce0..579c527b30 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java @@ -20,13 +20,13 @@ import org.springframework.data.domain.Range; import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; import org.springframework.data.redis.connection.stream.ReadOffset; 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.RedisZSetCommands.Limit; import org.springframework.lang.Nullable; /** diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java index 0fbe1dc780..b440ba08f3 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java @@ -22,10 +22,10 @@ import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.lang.Nullable; diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java index 101f5d0ce9..9cf9e65ba5 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java @@ -30,8 +30,8 @@ import org.springframework.core.convert.ConversionService; import org.springframework.data.domain.Range; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.ReactiveStreamCommands; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.stream.ByteBufferRecord; import org.springframework.data.redis.connection.stream.Consumer; diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java index 02585b5dfc..c2e0413212 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java @@ -27,13 +27,14 @@ import java.util.function.Function; import org.reactivestreams.Publisher; + import org.springframework.data.domain.Range; -import org.springframework.data.redis.connection.DefaultTuple; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.ReactiveZSetCommands; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.util.ByteUtils; diff --git a/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java index f5359c3319..de5a95577f 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultStreamOperations.java @@ -24,8 +24,8 @@ import org.springframework.core.convert.ConversionService; import org.springframework.data.domain.Range; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.stream.ByteRecord; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; diff --git a/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java index 8c1d072882..e04838179e 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java @@ -22,12 +22,12 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.lang.Nullable; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java index 0df964e9c7..ff6e662f3c 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java @@ -22,24 +22,14 @@ import java.util.Map; import org.reactivestreams.Publisher; + import org.springframework.data.domain.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; -import org.springframework.data.redis.connection.stream.ByteBufferRecord; -import org.springframework.data.redis.connection.stream.Consumer; -import org.springframework.data.redis.connection.stream.MapRecord; -import org.springframework.data.redis.connection.stream.ObjectRecord; -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.ReadOffset; +import org.springframework.data.redis.connection.Limit; +import org.springframework.data.redis.connection.stream.*; import org.springframework.data.redis.connection.stream.Record; -import org.springframework.data.redis.connection.stream.RecordId; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoConsumer; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoGroup; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoStream; -import org.springframework.data.redis.connection.stream.StreamOffset; -import org.springframework.data.redis.connection.stream.StreamReadOptions; -import org.springframework.data.redis.connection.stream.StreamRecords; import org.springframework.data.redis.hash.HashMapper; import org.springframework.lang.Nullable; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java index f6b51f9bac..a2f2d0aff5 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveZSetOperations.java @@ -24,10 +24,10 @@ import java.util.List; import org.springframework.data.domain.Range; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; /** diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index dc35f5eec0..1ddc971e9d 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -36,8 +36,8 @@ import org.springframework.data.redis.connection.RedisKeyCommands; import org.springframework.data.redis.connection.RedisServerCommands; import org.springframework.data.redis.connection.RedisTxCommands; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.SortParameters; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.data.redis.core.query.QueryUtils; import org.springframework.data.redis.core.query.SortQuery; diff --git a/src/main/java/org/springframework/data/redis/core/StreamOperations.java b/src/main/java/org/springframework/data/redis/core/StreamOperations.java index c9498dee58..e0f758cc24 100644 --- a/src/main/java/org/springframework/data/redis/core/StreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/StreamOperations.java @@ -22,23 +22,12 @@ import java.util.Map; import org.springframework.data.domain.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; -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.ObjectRecord; -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.ReadOffset; +import org.springframework.data.redis.connection.Limit; +import org.springframework.data.redis.connection.stream.*; import org.springframework.data.redis.connection.stream.Record; -import org.springframework.data.redis.connection.stream.RecordId; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoConsumers; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoGroups; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoStream; -import org.springframework.data.redis.connection.stream.StreamOffset; -import org.springframework.data.redis.connection.stream.StreamReadOptions; -import org.springframework.data.redis.connection.stream.StreamRecords; import org.springframework.data.redis.hash.HashMapper; import org.springframework.lang.Nullable; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/redis/core/ZSetOperations.java b/src/main/java/org/springframework/data/redis/core/ZSetOperations.java index c237bd3c41..33469a2fec 100644 --- a/src/main/java/org/springframework/data/redis/core/ZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ZSetOperations.java @@ -22,11 +22,11 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.lang.Nullable; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java index dfdec74d01..f28421c2a5 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java +++ b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java @@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.DataType; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.core.BoundZSetOperations; import org.springframework.data.redis.core.ConvertingCursor; diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java b/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java index 44784c9e26..3d2db6f586 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java @@ -23,9 +23,9 @@ import java.util.SortedSet; import java.util.concurrent.TimeUnit; -import org.springframework.data.redis.connection.RedisZSetCommands; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.core.BoundZSetOperations; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; @@ -333,7 +333,7 @@ default Set reverseRangeByLex(Range range) { Set reverseRangeByScore(double min, double max); /** - * Get set of {@link RedisZSetCommands.Tuple}s between {@code start} and {@code end} from sorted set. + * Get set of {@link Tuple}s between {@code start} and {@code end} from sorted set. * * @param start * @param end @@ -342,8 +342,7 @@ default Set reverseRangeByLex(Range range) { Set> rangeWithScores(long start, long end); /** - * Get set of {@link RedisZSetCommands.Tuple}s in range from {@code start} to {@code end} from sorted set ordered from - * high to low. + * Get set of {@link Tuple}s in range from {@code start} to {@code end} from sorted set ordered from high to low. * * @param start * @param end @@ -352,7 +351,7 @@ default Set reverseRangeByLex(Range range) { Set> reverseRangeWithScores(long start, long end); /** - * Get set of {@link RedisZSetCommands.Tuple}s where score is between {@code min} and {@code max} from sorted set. + * Get set of {@link Tuple}s where score is between {@code min} and {@code max} from sorted set. * * @param min * @param max @@ -361,8 +360,8 @@ default Set reverseRangeByLex(Range range) { Set> rangeByScoreWithScores(double min, double max); /** - * Get set of {@link RedisZSetCommands.Tuple}s where score is between {@code min} and {@code max} from sorted set - * ordered from high to low. + * Get set of {@link Tuple}s where score is between {@code min} and {@code max} from sorted set ordered from high to + * low. * * @param min * @param max diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensions.kt index 04c07bd990..0b858c834b 100644 --- a/src/main/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensions.kt +++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensions.kt @@ -20,7 +20,7 @@ import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.reactive.asPublisher import kotlinx.coroutines.reactive.awaitSingle import org.springframework.data.domain.Range -import org.springframework.data.redis.connection.RedisZSetCommands.Limit +import org.springframework.data.redis.connection.Limit import org.springframework.data.redis.connection.stream.* /** diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt index d6cdaaef04..03ead1eb69 100644 --- a/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt +++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt @@ -20,9 +20,10 @@ import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactive.awaitSingle import org.springframework.data.domain.Range +import org.springframework.data.redis.connection.Limit import org.springframework.data.redis.connection.RedisZSetCommands -import org.springframework.data.redis.connection.RedisZSetCommands.Limit -import org.springframework.data.redis.core.ZSetOperations.* +import org.springframework.data.redis.connection.zset.Weights +import org.springframework.data.redis.core.ZSetOperations.TypedTuple /** * Coroutines variant of [ReactiveZSetOperations.add]. @@ -237,8 +238,14 @@ suspend fun ReactiveZSetOperations.unionAndStoreAndAwai * @author Mark Paluch * @since 2.2 */ -suspend fun ReactiveZSetOperations.unionAndStoreAndAwait(key: K, otherKeys: Collection, destKey: K, aggregate: RedisZSetCommands.Aggregate, weights: RedisZSetCommands.Weights): Long = - unionAndStore(key, otherKeys, destKey, aggregate, weights).awaitSingle() +suspend fun ReactiveZSetOperations.unionAndStoreAndAwait( + key: K, + otherKeys: Collection, + destKey: K, + aggregate: RedisZSetCommands.Aggregate, + weights: Weights +): Long = + unionAndStore(key, otherKeys, destKey, aggregate, weights).awaitSingle() /** * Coroutines variant of [ReactiveZSetOperations.intersectAndStore]. @@ -273,8 +280,14 @@ suspend fun ReactiveZSetOperations.intersectAndStoreAnd * @author Mark Paluch * @since 2.2 */ -suspend fun ReactiveZSetOperations.intersectAndStoreAndAwait(key: K, otherKeys: Collection, destKey: K, aggregate: RedisZSetCommands.Aggregate, weights: RedisZSetCommands.Weights): Long = - intersectAndStore(key, otherKeys, destKey, aggregate, weights).awaitSingle() +suspend fun ReactiveZSetOperations.intersectAndStoreAndAwait( + key: K, + otherKeys: Collection, + destKey: K, + aggregate: RedisZSetCommands.Aggregate, + weights: Weights +): Long = + intersectAndStore(key, otherKeys, destKey, aggregate, weights).awaitSingle() /** * Coroutines variant of [ReactiveZSetOperations.rangeByLex]. diff --git a/src/test/java/org/springframework/data/redis/VersionParserUnitTests.java b/src/test/java/org/springframework/data/redis/VersionParserUnitTests.java deleted file mode 100644 index c1f6c22da2..0000000000 --- a/src/test/java/org/springframework/data/redis/VersionParserUnitTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014-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; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.Test; - -/** - * @author Christoph Strobl - */ -class VersionParserUnitTests { - - @Test - void shouldParseNullToUnknown() { - assertThat(VersionParser.parseVersion(null)).isEqualTo(Version.UNKNOWN); - } - - @Test - void shouldParseEmptyVersionStringToUnknown() { - assertThat(VersionParser.parseVersion("")).isEqualTo(Version.UNKNOWN); - } - - @Test - void shouldParseInvalidVersionStringToUnknown() { - assertThat(VersionParser.parseVersion("ThisIsNoValidVersion")).isEqualTo(Version.UNKNOWN); - } - - @Test - void shouldParseMajorMinorWithoutPatchCorrectly() { - assertThat(VersionParser.parseVersion("1.2")).isEqualTo(new Version(1, 2, 0)); - } - - @Test - void shouldParseMajorMinorPatchCorrectly() { - assertThat(VersionParser.parseVersion("1.2.3")).isEqualTo(new Version(1, 2, 3)); - } - - @Test - void shouldParseMajorWithoutMinorPatchCorrectly() { - assertThat(VersionParser.parseVersion("1.2.3.a")).isEqualTo(new Version(1, 2, 3)); - } -} 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 ef1db3db57..e62c1689a5 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -59,9 +59,7 @@ import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.RedisZSetCommands.ZAddArgs; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; @@ -76,6 +74,8 @@ import org.springframework.data.redis.connection.stream.StreamInfo.XInfoGroups; import org.springframework.data.redis.connection.stream.StreamInfo.XInfoStream; import org.springframework.data.redis.connection.stream.StreamOffset; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyScanOptions; import org.springframework.data.redis.core.ScanOptions; diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java index 7c500100e5..8d82616931 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java @@ -50,9 +50,6 @@ import org.springframework.data.redis.connection.RedisStreamCommands.XAddOptions; import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.stream.Consumer; @@ -61,6 +58,9 @@ import org.springframework.data.redis.connection.stream.StreamOffset; import org.springframework.data.redis.connection.stream.StreamReadOptions; import org.springframework.data.redis.connection.stream.StreamRecords; +import org.springframework.data.redis.connection.zset.DefaultTuple; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.serializer.StringRedisSerializer; /** diff --git a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java index 31de230460..88252f9688 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java @@ -35,6 +35,8 @@ import org.springframework.data.geo.Metric; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.RedisNode.RedisNodeBuilder; +import org.springframework.data.redis.connection.zset.Tuple; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.types.Expiration; @@ -938,12 +940,13 @@ public Set zRangeByLex(byte[] key, Range range) { } @Override - public Set zRangeByLex(byte[] key, Range range, Limit limit) { + public Set zRangeByLex(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return delegate.zRangeByLex(key, range, limit); } @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { return delegate.zRangeByScoreWithScores(key, range, limit); } @@ -953,12 +956,14 @@ public Set zRevRangeByScore(byte[] key, Range range) { } @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScore(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { return delegate.zRevRangeByScore(key, range, limit); } @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScoreWithScores(byte[] key, Range range, + org.springframework.data.redis.connection.Limit limit) { return delegate.zRevRangeByScoreWithScores(key, range, limit); } @@ -983,7 +988,7 @@ public Set zRangeByScore(byte[] key, Range range) { } @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRangeByScore(byte[] key, Range range, org.springframework.data.redis.connection.Limit limit) { return delegate.zRangeByScore(key, range, limit); } diff --git a/src/test/java/org/springframework/data/redis/connection/WeightsUnitTests.java b/src/test/java/org/springframework/data/redis/connection/WeightsUnitTests.java index fe936b69dd..f542252168 100644 --- a/src/test/java/org/springframework/data/redis/connection/WeightsUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/WeightsUnitTests.java @@ -15,14 +15,14 @@ */ package org.springframework.data.redis.connection; -import org.junit.jupiter.api.Test; - import static org.assertj.core.api.Assertions.*; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.junit.jupiter.api.Test; + +import org.springframework.data.redis.connection.zset.Weights; /** - * Unit tests for {@link org.springframework.data.redis.connection.RedisZSetCommands.Weights}. + * Unit tests for {@link Weights}. * * @author Mark Paluch */ 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 17d9ca7314..85cbe699e3 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 @@ -56,7 +56,7 @@ import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.DefaultSortParameters; -import org.springframework.data.redis.connection.DefaultTuple; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; @@ -65,6 +65,8 @@ import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.ValueEncoding.RedisValueEncoding; +import org.springframework.data.redis.connection.zset.DefaultTuple; +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.data.redis.core.script.DigestUtils; 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 fc2f7a67e4..256b3d4a12 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 @@ -37,7 +37,7 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.redis.connection.AbstractConnectionUnitTestBase; import org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption; -import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; +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; 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 e5d63fc334..76642af095 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 @@ -49,12 +49,15 @@ import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.*; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisListCommands.Position; import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.ValueEncoding.RedisValueEncoding; +import org.springframework.data.redis.connection.zset.DefaultTuple; +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.data.redis.core.types.Expiration; diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java index 0838b5cee6..df1e856552 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java @@ -40,7 +40,6 @@ import org.springframework.data.redis.connection.RedisPassword; import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; -import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; @@ -204,15 +203,15 @@ void toSetArgsShouldNotSetNxOrXxForUpsert() { @Test // DATAREDIS-981 void toLimit() { - Limit limit = LettuceConverters.toLimit(RedisZSetCommands.Limit.unlimited()); + Limit limit = LettuceConverters.toLimit(org.springframework.data.redis.connection.Limit.unlimited()); assertThat(limit.isLimited()).isFalse(); assertThat(limit.getCount()).isEqualTo(-1L); - limit = LettuceConverters.toLimit(RedisZSetCommands.Limit.limit().count(-1)); + limit = LettuceConverters.toLimit(org.springframework.data.redis.connection.Limit.limit().count(-1)); assertThat(limit.isLimited()).isTrue(); assertThat(limit.getCount()).isEqualTo(-1L); - limit = LettuceConverters.toLimit(RedisZSetCommands.Limit.limit().count(5)); + limit = LettuceConverters.toLimit(org.springframework.data.redis.connection.Limit.limit().count(5)); assertThat(limit.isLimited()).isTrue(); assertThat(limit.getCount()).isEqualTo(5L); } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommandsIntegrationTests.java index d459b68e24..87b742b400 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStreamCommandsIntegrationTests.java @@ -28,8 +28,8 @@ import org.springframework.data.domain.Range; import org.springframework.data.redis.RedisSystemException; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisStreamCommands.XClaimOptions; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.ReadOffset; import org.springframework.data.redis.connection.stream.RecordId; diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java index 11e29e22a7..7d952b74a1 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommandsIntegrationTests.java @@ -26,7 +26,7 @@ import java.util.Arrays; import org.springframework.data.domain.Range; -import org.springframework.data.redis.connection.DefaultTuple; +import org.springframework.data.redis.connection.zset.DefaultTuple; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.test.condition.EnabledOnCommand; import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest; diff --git a/src/test/java/org/springframework/data/redis/core/DefaultReactiveStreamOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultReactiveStreamOperationsIntegrationTests.java index 7ecf513681..499dfb6bbf 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultReactiveStreamOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultReactiveStreamOperationsIntegrationTests.java @@ -30,9 +30,9 @@ import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.Person; import org.springframework.data.redis.PersonObjectFactory; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.stream.Consumer; import org.springframework.data.redis.connection.stream.MapRecord; import org.springframework.data.redis.connection.stream.ReadOffset; diff --git a/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java index a5a2f3e81b..654f8d83bf 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultReactiveZSetOperationsIntegrationTests.java @@ -32,11 +32,11 @@ import org.springframework.data.domain.Range; import org.springframework.data.redis.ByteBufferObjectFactory; import org.springframework.data.redis.ObjectFactory; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ReactiveOperationsTestParams.Fixture; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; diff --git a/src/test/java/org/springframework/data/redis/core/DefaultStreamOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultStreamOperationsIntegrationTests.java index 8a6410fa9e..895e921ad9 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultStreamOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultStreamOperationsIntegrationTests.java @@ -29,8 +29,8 @@ import org.springframework.data.domain.Range.Bound; import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.Person; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.jedis.extension.JedisConnectionFactoryExtension; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.connection.lettuce.extension.LettuceConnectionFactoryExtension; diff --git a/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsIntegrationTests.java index 93a036b7a4..ae9347c3b4 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultZSetOperationsIntegrationTests.java @@ -35,8 +35,9 @@ import org.springframework.data.redis.LongObjectFactory; import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.RawObjectFactory; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands; -import org.springframework.data.redis.connection.RedisZSetCommands.Weights; +import org.springframework.data.redis.connection.zset.Weights; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.data.redis.test.condition.EnabledOnCommand; import org.springframework.data.redis.test.extension.parametrized.MethodSource; @@ -348,7 +349,7 @@ void testRangeByLexUnboundedWithLimit() { zSetOps.add(key, value2, 3.7); zSetOps.add(key, value3, 5.8); Set tuples = zSetOps.rangeByLex(key, RedisZSetCommands.Range.unbounded(), - RedisZSetCommands.Limit.limit().count(2).offset(1)); + Limit.limit().count(2).offset(1)); assertThat(tuples).hasSize(2).containsSequence(value2, value3); } @@ -368,7 +369,7 @@ void testReverseRangeByLexUnboundedWithLimit() { zSetOps.add(key, value2, 3.7); zSetOps.add(key, value3, 5.8); Set tuples = zSetOps.reverseRangeByLex(key, RedisZSetCommands.Range.unbounded(), - RedisZSetCommands.Limit.limit().count(2).offset(1)); + Limit.limit().count(2).offset(1)); assertThat(tuples).hasSize(2).containsSequence(value2, value1); } @@ -388,7 +389,7 @@ void testRangeByLexBoundedWithLimit() { zSetOps.add(key, value2, 3.7); zSetOps.add(key, value3, 5.8); Set tuples = zSetOps.rangeByLex(key, RedisZSetCommands.Range.range().gte(value1), - RedisZSetCommands.Limit.limit().count(1).offset(1)); + Limit.limit().count(1).offset(1)); assertThat(tuples).hasSize(1).startsWith(value2); } diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java index 4587161500..15bcc2ac58 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java @@ -34,6 +34,7 @@ import org.springframework.data.redis.LongAsStringObjectFactory; import org.springframework.data.redis.LongObjectFactory; import org.springframework.data.redis.ObjectFactory; +import org.springframework.data.redis.connection.Limit; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.core.BoundZSetOperations; import org.springframework.data.redis.core.Cursor; @@ -441,7 +442,7 @@ void testRangeByLexUnboundedWithLimit() { zSet.add(t2, 2); zSet.add(t3, 3); Set tuples = zSet.rangeByLex(RedisZSetCommands.Range.unbounded(), - RedisZSetCommands.Limit.limit().count(1).offset(1)); + Limit.limit().count(1).offset(1)); assertThat(tuples).hasSize(1); T tuple = tuples.iterator().next(); @@ -462,7 +463,7 @@ void testRangeByLexBoundedWithLimit() { zSet.add(t2, 2); zSet.add(t3, 3); Set tuples = zSet.rangeByLex(RedisZSetCommands.Range.range().gte(t1), - RedisZSetCommands.Limit.limit().count(2).offset(1)); + Limit.limit().count(2).offset(1)); assertThat(tuples).hasSize(2).containsSequence(t2, t3); } @@ -481,7 +482,7 @@ void testReverseRangeByLexBoundedWithLimit() { zSet.add(t2, 2); zSet.add(t3, 3); Set tuples = zSet.reverseRangeByLex(RedisZSetCommands.Range.range().gte(t1), - RedisZSetCommands.Limit.limit().count(2).offset(1)); + Limit.limit().count(2).offset(1)); assertThat(tuples).hasSize(2).containsSequence(t2, t1); } diff --git a/src/test/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensionsUnitTests.kt b/src/test/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensionsUnitTests.kt index 14a2ed8aa3..e2425e099d 100644 --- a/src/test/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensionsUnitTests.kt +++ b/src/test/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensionsUnitTests.kt @@ -25,7 +25,7 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.reactivestreams.Publisher import org.springframework.data.domain.Range -import org.springframework.data.redis.connection.RedisZSetCommands.Limit +import org.springframework.data.redis.connection.Limit import org.springframework.data.redis.connection.stream.* import reactor.core.publisher.Flux import reactor.core.publisher.Mono diff --git a/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt b/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt index 4c30996ab1..36821190bf 100644 --- a/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt +++ b/src/test/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensionsUnitTests.kt @@ -23,10 +23,10 @@ import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.springframework.data.domain.Range -import org.springframework.data.redis.connection.RedisZSetCommands +import org.springframework.data.redis.connection.Limit import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate -import org.springframework.data.redis.connection.RedisZSetCommands.Weights -import org.springframework.data.redis.core.ZSetOperations.* +import org.springframework.data.redis.connection.zset.Weights +import org.springframework.data.redis.core.ZSetOperations.TypedTuple import reactor.core.publisher.Flux import reactor.core.publisher.Mono @@ -204,7 +204,7 @@ class ReactiveZSetOperationsExtensionsUnitTests { } verify { - operations.rangeByScore("foo", range, RedisZSetCommands.Limit.unlimited()) + operations.rangeByScore("foo", range, Limit.unlimited()) } } @@ -221,7 +221,7 @@ class ReactiveZSetOperationsExtensionsUnitTests { } verify { - operations.rangeByScoreWithScores("foo", range, RedisZSetCommands.Limit.unlimited()) + operations.rangeByScoreWithScores("foo", range, Limit.unlimited()) } } @@ -270,7 +270,7 @@ class ReactiveZSetOperationsExtensionsUnitTests { } verify { - operations.reverseRangeByScore("foo", range, RedisZSetCommands.Limit.unlimited()) + operations.reverseRangeByScore("foo", range, Limit.unlimited()) } } @@ -287,7 +287,7 @@ class ReactiveZSetOperationsExtensionsUnitTests { } verify { - operations.reverseRangeByScoreWithScores("foo", range, RedisZSetCommands.Limit.unlimited()) + operations.reverseRangeByScoreWithScores("foo", range, Limit.unlimited()) } } @@ -527,7 +527,7 @@ class ReactiveZSetOperationsExtensionsUnitTests { } verify { - operations.rangeByLex("foo", Range.just("bar"), RedisZSetCommands.Limit.unlimited()) + operations.rangeByLex("foo", Range.just("bar"), Limit.unlimited()) } } @@ -542,7 +542,7 @@ class ReactiveZSetOperationsExtensionsUnitTests { } verify { - operations.reverseRangeByLex("foo", Range.just("bar"), RedisZSetCommands.Limit.unlimited()) + operations.reverseRangeByLex("foo", Range.just("bar"), Limit.unlimited()) } } From 850cb38b5328a3b4d808ad41635f32d12961eecd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 23 Feb 2022 11:17:04 +0100 Subject: [PATCH 05/12] Remove deprecated API. --- .../redis/cache/RedisCacheConfiguration.java | 29 -- ...usterCommandExecutionFailureException.java | 13 - .../DefaultStringRedisConnection.java | 8 - .../connection/DefaultedRedisConnection.java | 7 - .../data/redis/connection/Pool.java | 45 --- .../data/redis/connection/PoolConfig.java | 37 -- .../redis/connection/ReactiveKeyCommands.java | 10 - .../redis/connection/RedisServerCommands.java | 11 - .../jedis/JedisClusterConnection.java | 2 +- .../connection/jedis/JedisConnection.java | 6 +- .../jedis/JedisConnectionFactory.java | 89 +---- .../connection/jedis/JedisConverters.java | 93 +----- .../jedis/JedisExceptionConverter.java | 2 + .../redis/connection/jedis/JedisUtils.java | 315 ------------------ .../connection/jedis/JedisVersionUtil.java | 96 ------ .../connection/lettuce/LettuceConverters.java | 7 +- .../LettuceReactiveClusterKeyCommands.java | 10 +- .../lettuce/LettuceReactiveKeyCommands.java | 8 +- .../data/redis/core/AbstractOperations.java | 2 +- .../data/redis/core/BoundGeoOperations.java | 210 +----------- .../data/redis/core/ConvertingCursor.java | 10 +- .../data/redis/core/Cursor.java | 10 - .../redis/core/DefaultBoundGeoOperations.java | 2 +- .../data/redis/core/GeoOperations.java | 221 ------------ .../data/redis/core/RedisCommand.java | 2 - .../data/redis/core/RedisConnectionUtils.java | 16 - .../data/redis/core/RedisKeyValueAdapter.java | 16 - .../data/redis/core/RedisTemplate.java | 2 +- .../redis/core/convert/CustomConversions.java | 47 --- .../core/convert/MappingRedisConverter.java | 12 - .../data/redis/hash/ObjectHashMapper.java | 15 +- .../StreamMessageListenerContainer.java | 22 -- .../ClusterCommandExecutorUnitTests.java | 4 +- .../connection/RedisConnectionUnitTests.java | 4 - ...edisConnectionFactoryIntegrationTests.java | 15 - .../core/RedisConnectionUtilsUnitTests.java | 2 +- 36 files changed, 43 insertions(+), 1357 deletions(-) delete mode 100644 src/main/java/org/springframework/data/redis/connection/Pool.java delete mode 100644 src/main/java/org/springframework/data/redis/connection/PoolConfig.java delete mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java delete mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisVersionUtil.java delete mode 100644 src/main/java/org/springframework/data/redis/core/convert/CustomConversions.java diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java b/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java index 8aa8fe9bc7..07bc8190d9 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java @@ -17,7 +17,6 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; -import java.util.Optional; import java.util.function.Consumer; import org.springframework.cache.Cache; @@ -143,25 +142,6 @@ public RedisCacheConfiguration entryTtl(Duration ttl) { valueSerializationPair, conversionService); } - /** - * Use the given prefix instead of using the cache name.
- * This option replaces the cache name with {@code prefix} therefore we recommend rather using - * {@link #prefixCacheNameWith(String)} or {@link #computePrefixWith(CacheKeyPrefix)} for more control.
- * The generated cache key will be: {@code prefix + cache entry key}. - * - * @param prefix must not be {@literal null}. - * @return new {@link RedisCacheConfiguration}. - * @deprecated since 2.3. Use {@link #prefixCacheNameWith(String)} or {@link #computePrefixWith(CacheKeyPrefix)} - * instead. - */ - @Deprecated - public RedisCacheConfiguration prefixKeysWith(String prefix) { - - Assert.notNull(prefix, "Prefix must not be null!"); - - return computePrefixWith((cacheName) -> prefix); - } - /** * Prefix the {@link RedisCache#getName() cache name} with the given value.
* The generated cache key will be: {@code prefix + cache name + "::" + cache entry key}. @@ -261,15 +241,6 @@ public RedisCacheConfiguration serializeValuesWith(SerializationPair valueSer valueSerializationPair, conversionService); } - /** - * @return never {@literal null}. - * @deprecated since 2.0.4. Please use {@link #getKeyPrefixFor(String)}. - */ - @Deprecated - public Optional getKeyPrefix() { - return usePrefix() ? Optional.of(keyPrefix.compute("")) : Optional.empty(); - } - /** * Get the computed {@literal key} prefix for a given {@literal cacheName}. * diff --git a/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutionFailureException.java b/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutionFailureException.java index 51fba4f18d..4b6a9ab280 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutionFailureException.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutionFailureException.java @@ -15,7 +15,6 @@ */ package org.springframework.data.redis.connection; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -32,8 +31,6 @@ public class ClusterCommandExecutionFailureException extends UncategorizedDataAc private static final long serialVersionUID = 5727044227040368955L; - private final Collection causes; - /** * Creates new {@link ClusterCommandExecutionFailureException}. * @@ -51,18 +48,8 @@ public ClusterCommandExecutionFailureException(Throwable cause) { public ClusterCommandExecutionFailureException(List causes) { super(causes.get(0).getMessage(), causes.get(0)); - this.causes = causes; causes.forEach(this::addSuppressed); } - /** - * Get the collected errors. - * - * @return never {@literal null}. - * @deprecated since 2.0, use {@link #getSuppressed()}. - */ - public Collection getCauses() { - return causes; - } } diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 500b1a2b61..168ac801a7 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -198,14 +198,6 @@ public void bgReWriteAof() { delegate.bgReWriteAof(); } - /** - * @deprecated As of 1.3, use {@link #bgReWriteAof}. - */ - @Deprecated - public void bgWriteAof() { - bgReWriteAof(); - } - @Override public List bLPop(int timeout, byte[]... keys) { return convertAndReturn(delegate.bLPop(timeout, keys), Converters.identityConverter()); diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java index 773d37d8c5..0fd81134ed 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -1589,13 +1589,6 @@ default void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { // SERVER COMMANDS - /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ - @Override - @Deprecated - default void bgWriteAof() { - serverCommands().bgWriteAof(); - } - /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ @Override @Deprecated diff --git a/src/main/java/org/springframework/data/redis/connection/Pool.java b/src/main/java/org/springframework/data/redis/connection/Pool.java deleted file mode 100644 index 8c7a033f30..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/Pool.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011-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; - -/** - * Pool of resources - * - * @author Jennifer Hickey - */ -public interface Pool { - - /** - * @return A resource, if available - */ - T getResource(); - - /** - * @param resource A broken resource that should be invalidated - */ - void returnBrokenResource(final T resource); - - /** - * @param resource A resource to return to the pool - */ - void returnResource(final T resource); - - /** - * Destroys the pool - */ - void destroy(); - -} diff --git a/src/main/java/org/springframework/data/redis/connection/PoolConfig.java b/src/main/java/org/springframework/data/redis/connection/PoolConfig.java deleted file mode 100644 index 180d144b1c..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/PoolConfig.java +++ /dev/null @@ -1,37 +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; - -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; - -/** - * Subclass of {@link GenericObjectPoolConfig} that includes setters for instantiation in Spring - * - * @author Jennifer Hickey - * @author Christoph Strobl - * @deprecated use {@link GenericObjectPoolConfig} instead. Will be removed in a future revision. - */ -@Deprecated -public class PoolConfig extends GenericObjectPoolConfig { - - public PoolConfig() { - super(); - } - - public void setMaxActive(int maxActive) { - setMaxTotal(maxActive); - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java index a8438fb8dd..3ab7d99d46 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java @@ -346,16 +346,6 @@ public RenameCommand to(ByteBuffer newKey) { return new RenameCommand(getKey(), newKey); } - /** - * @return can be {@literal null}. - * @deprecated since 2.5.7, renamed to {@link #getNewKey()}. - */ - @Nullable - @Deprecated - public ByteBuffer getNewName() { - return newKey; - } - /** * @return can be {@literal null}. * @since 2.5.7 diff --git a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java index 25fff02b4e..095e5f3da5 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java @@ -43,17 +43,6 @@ enum MigrateOption { COPY, REPLACE } - /** - * Start an {@literal Append Only File} rewrite process on server. - * - * @deprecated As of 1.3, use {@link #bgReWriteAof}. - * @see Redis Documentation: BGREWRITEAOF - */ - @Deprecated - default void bgWriteAof() { - bgReWriteAof(); - } - /** * Start an {@literal Append Only File} rewrite process on server. * 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 a8037fee9e..bdbbc5e9d1 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 @@ -75,7 +75,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy( - JedisConverters.exceptionConverter()); + JedisExceptionConverter.INSTANCE); private static final byte[][] EMPTY_2D_BYTE_ARRAY = new byte[0][]; 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 70c74adb1d..92fc89c681 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 @@ -61,7 +61,7 @@ public class JedisConnection extends AbstractRedisConnection { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy( - JedisConverters.exceptionConverter()); + JedisExceptionConverter.INSTANCE); private final Jedis jedis; @@ -417,7 +417,7 @@ public List exec() { try { if (isPipelined()) { pipeline(newJedisResult(getRequiredPipeline().exec(), - new TransactionResultConverter<>(new LinkedList<>(txResults), JedisConverters.exceptionConverter()))); + new TransactionResultConverter<>(new LinkedList<>(txResults), JedisExceptionConverter.INSTANCE))); return null; } @@ -428,7 +428,7 @@ public List exec() { List results = transaction.exec(); return !CollectionUtils.isEmpty(results) - ? new TransactionResultConverter<>(txResults, JedisConverters.exceptionConverter()).convert(results) + ? new TransactionResultConverter<>(txResults, JedisExceptionConverter.INSTANCE).convert(results) : results; } catch (Exception ex) { throw convertJedisAccessException(ex); 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 ee367bdaf2..c1d751e8d9 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 @@ -61,7 +61,6 @@ import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; /** * Connection factory creating Jedis based connections. @@ -90,12 +89,10 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, private final static Log log = LogFactory.getLog(JedisConnectionFactory.class); private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy( - JedisConverters.exceptionConverter()); + JedisExceptionConverter.INSTANCE); private final JedisClientConfiguration clientConfiguration; - private @Nullable JedisShardInfo shardInfo; private JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().build(); - private boolean providedShardInfo = false; private @Nullable Pool pool; private boolean convertPipelineAndTxResults = true; private RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration("localhost", @@ -131,23 +128,6 @@ private JedisConnectionFactory(JedisClientConfiguration clientConfig) { this.clientConfiguration = clientConfig; } - /** - * Constructs a new JedisConnectionFactory instance. Will override the other connection parameters passed - * to the factory. - * - * @param shardInfo shard information - * @deprecated since 2.0, configure Jedis with {@link JedisClientConfiguration} and - * {@link RedisStandaloneConfiguration}. - */ - @Deprecated - public JedisConnectionFactory(JedisShardInfo shardInfo) { - - this(MutableJedisClientConfiguration.create(shardInfo)); - - this.shardInfo = shardInfo; - this.providedShardInfo = true; - } - /** * Constructs a new JedisConnectionFactory instance using the given pool configuration. * @@ -176,7 +156,7 @@ public JedisConnectionFactory(RedisSentinelConfiguration sentinelConfig) { * @param poolConfig pool configuration. Defaulted to new instance if {@literal null}. * @since 1.4 */ - public JedisConnectionFactory(RedisSentinelConfiguration sentinelConfig, JedisPoolConfig poolConfig) { + public JedisConnectionFactory(RedisSentinelConfiguration sentinelConfig, @Nullable JedisPoolConfig poolConfig) { this.configuration = sentinelConfig; this.clientConfiguration = MutableJedisClientConfiguration @@ -295,10 +275,6 @@ protected Jedis fetchJedisConnector() { private Jedis createJedis() { - if (providedShardInfo) { - return new Jedis(getShardInfo()); - } - return new Jedis(new HostAndPort(getHostName(), getPort()), this.clientConfig); } @@ -317,29 +293,6 @@ public void afterPropertiesSet() { clientConfig = createClientConfig(getDatabase(), getRedisUsername(), getRedisPassword()); - if (shardInfo == null && clientConfiguration instanceof MutableJedisClientConfiguration) { - - providedShardInfo = false; - shardInfo = new JedisShardInfo(getHostName(), getPort(), isUseSsl(), // - clientConfiguration.getSslSocketFactory().orElse(null), // - clientConfiguration.getSslParameters().orElse(null), // - clientConfiguration.getHostnameVerifier().orElse(null)); - - getRedisPassword().map(String::new).ifPresent(shardInfo::setPassword); - String username = getRedisUsername(); - if (StringUtils.hasText(username)) { - shardInfo.setUser(username); - } - - int readTimeout = getReadTimeout(); - - if (readTimeout > 0) { - shardInfo.setSoTimeout(readTimeout); - } - - getMutableConfiguration().setShardInfo(shardInfo); - } - if (getUsePool() && !isRedisClusterAware()) { this.pool = createPool(); } @@ -630,34 +583,6 @@ public void setPort(int port) { standaloneConfig.setPort(port); } - /** - * Returns the shardInfo. - * - * @return the shardInfo. - * @deprecated since 2.0. - */ - @Deprecated - @Nullable - public JedisShardInfo getShardInfo() { - return shardInfo; - } - - /** - * Sets the shard info for this factory. - * - * @param shardInfo the shardInfo to set. - * @deprecated since 2.0, configure the individual properties from {@link JedisShardInfo} using - * {@link JedisClientConfiguration}. - * @throws IllegalStateException if {@link JedisClientConfiguration} is immutable. - */ - @Deprecated - public void setShardInfo(JedisShardInfo shardInfo) { - - this.shardInfo = shardInfo; - this.providedShardInfo = true; - getMutableConfiguration().setShardInfo(shardInfo); - } - /** * Returns the timeout. * @@ -968,7 +893,6 @@ static class MutableJedisClientConfiguration implements JedisClientConfiguration public static JedisClientConfiguration create(JedisShardInfo shardInfo) { MutableJedisClientConfiguration configuration = new MutableJedisClientConfiguration(); - configuration.setShardInfo(shardInfo); return configuration; } @@ -1060,14 +984,5 @@ public void setConnectTimeout(Duration connectTimeout) { this.connectTimeout = connectTimeout; } - public void setShardInfo(JedisShardInfo shardInfo) { - - setSslSocketFactory(shardInfo.getSslSocketFactory()); - setSslParameters(shardInfo.getSslParameters()); - setHostnameVerifier(shardInfo.getHostnameVerifier()); - setUseSsl(shardInfo.getSsl()); - setConnectTimeout(Duration.ofMillis(shardInfo.getConnectionTimeout())); - setReadTimeout(Duration.ofMillis(shardInfo.getSoTimeout())); - } } } 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 f915b49bd8..7595a3b694 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 @@ -40,7 +40,6 @@ import java.util.concurrent.TimeUnit; import org.springframework.core.convert.converter.Converter; -import org.springframework.dao.DataAccessException; import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResult; import org.springframework.data.geo.GeoResults; @@ -68,7 +67,6 @@ import org.springframework.data.redis.connection.ValueEncoding; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.convert.ListConverter; -import org.springframework.data.redis.connection.convert.MapConverter; import org.springframework.data.redis.connection.convert.SetConverter; import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; import org.springframework.data.redis.connection.zset.DefaultTuple; @@ -93,10 +91,9 @@ * @author Guy Korland * @author dengliming */ +@SuppressWarnings("ConstantConditions") public abstract class JedisConverters extends Converters { - private static final Converter EXCEPTION_CONVERTER = new JedisExceptionConverter(); - public static final byte[] PLUS_BYTES; public static final byte[] MINUS_BYTES; public static final byte[] POSITIVE_INFINITY_BYTES; @@ -120,56 +117,19 @@ public static Converter stringToBytes() { * @return * @since 1.4 */ - public static ListConverter tuplesToTuples() { + static ListConverter tuplesToTuples() { return new ListConverter<>(JedisConverters::toTuple); } - public static ListConverter stringListToByteList() { + static ListConverter stringListToByteList() { return new ListConverter<>(stringToBytes()); } /** * @deprecated since 2.5 */ - @Deprecated - public static SetConverter stringSetToByteSet() { - return new SetConverter<>(stringToBytes()); - } - - /** - * @deprecated since 2.5 - */ - @Deprecated - public static MapConverter stringMapToByteMap() { - return new MapConverter<>(stringToBytes()); - } - - /** - * @deprecated since 2.5 - */ - @Deprecated - public static SetConverter tupleSetToTupleSet() { - return new SetConverter<>(JedisConverters::toTuple); - } - - public static Converter exceptionConverter() { - return EXCEPTION_CONVERTER; - } - - public static String[] toStrings(byte[][] source) { - String[] result = new String[source.length]; - for (int i = 0; i < source.length; i++) { - result[i] = SafeEncoder.encode(source[i]); - } - return result; - } - - /** - * @deprecated since 2.5 - */ - @Deprecated - public static Set toTupleSet(Set source) { - return tupleSetToTupleSet().convert(source); + static Set toTupleSet(Set source) { + return new SetConverter<>(JedisConverters::toTuple).convert(source); } public static Tuple toTuple(redis.clients.jedis.Tuple source) { @@ -190,18 +150,8 @@ public static Map toTupleMap(Set tuples) { Map args = new LinkedHashMap<>(tuples.size(), 1); Set scores = new HashSet<>(tuples.size(), 1); - boolean isAtLeastJedis24 = JedisVersionUtil.atLeastJedis24(); - for (Tuple tuple : tuples) { - - if (!isAtLeastJedis24) { - if (scores.contains(tuple.getScore())) { - throw new UnsupportedOperationException( - "Bulk add of multiple elements with the same score is not supported. Add the elements individually."); - } - scores.add(tuple.getScore()); - } - + scores.add(tuple.getScore()); args.put(tuple.getValue(), tuple.getScore()); } @@ -290,14 +240,6 @@ public static List toListOfRedisServer(List> so return toList(it -> RedisServer.newServerFrom(Converters.toProperties(it)), source); } - /** - * @deprecated since 2.5 - */ - @Deprecated - public static DataAccessException toDataAccessException(Exception ex) { - return EXCEPTION_CONVERTER.convert(ex); - } - public static ListPosition toListPosition(Position source) { Assert.notNull(source, "list positions are mandatory"); return (Position.AFTER.equals(source) ? ListPosition.AFTER : ListPosition.BEFORE); @@ -436,10 +378,12 @@ public static SetParams toSetCommandExPxArgument(Expiration expiration, SetParam } if (expiration.getTimeUnit() == TimeUnit.MILLISECONDS) { - return expiration.isUnixTimestamp() ? paramsToUse.pxAt(expiration.getExpirationTime()) : paramsToUse.px(expiration.getExpirationTime()); + return expiration.isUnixTimestamp() ? paramsToUse.pxAt(expiration.getExpirationTime()) + : paramsToUse.px(expiration.getExpirationTime()); } - return expiration.isUnixTimestamp() ? paramsToUse.exAt(expiration.getConverted(TimeUnit.SECONDS)) : paramsToUse.ex(expiration.getConverted(TimeUnit.SECONDS)); + return expiration.isUnixTimestamp() ? paramsToUse.exAt(expiration.getConverted(TimeUnit.SECONDS)) + : paramsToUse.ex(expiration.getConverted(TimeUnit.SECONDS)); } /** @@ -605,26 +549,9 @@ private static List toList(Converter converter, @Nullable Collec return target; } - /** - * @deprecated since 2.5 - */ - @Deprecated - public static ListConverter bytesListToStringListConverter() { - return new ListConverter<>(JedisConverters::toString); - } - - /** - * @deprecated since 2.5 - */ - @Deprecated - public static ListConverter getBytesListToLongListConverter() { - return new ListConverter<>(JedisConverters::toLong); - } - /** * @return * @since 1.8 - * @deprecated since 2.5 */ public static ListConverter geoCoordinateToPointConverter() { return new ListConverter<>(JedisConverters::toPoint); 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 22392fee19..278793faf3 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 @@ -41,6 +41,8 @@ */ public class JedisExceptionConverter implements Converter { + static final JedisExceptionConverter INSTANCE = new JedisExceptionConverter(); + public DataAccessException convert(Exception ex) { if (ex instanceof DataAccessException) { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java deleted file mode 100644 index f87c5cb576..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisUtils.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2011-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 redis.clients.jedis.BinaryJedisPubSub; -import redis.clients.jedis.ListPosition; -import redis.clients.jedis.Protocol; -import redis.clients.jedis.SortingParams; -import redis.clients.jedis.exceptions.JedisConnectionException; -import redis.clients.jedis.exceptions.JedisDataException; -import redis.clients.jedis.exceptions.JedisException; -import redis.clients.jedis.util.SafeEncoder; - -import java.io.IOException; -import java.io.StringReader; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.TimeoutException; - -import org.springframework.dao.DataAccessException; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.redis.RedisConnectionFailureException; -import org.springframework.data.redis.RedisSystemException; -import org.springframework.data.redis.connection.MessageListener; -import org.springframework.data.redis.connection.RedisListCommands.Position; -import org.springframework.data.redis.connection.ReturnType; -import org.springframework.data.redis.connection.SortParameters; -import org.springframework.data.redis.connection.SortParameters.Order; -import org.springframework.data.redis.connection.SortParameters.Range; -import org.springframework.data.redis.connection.zset.DefaultTuple; -import org.springframework.data.redis.connection.zset.Tuple; -import org.springframework.util.Assert; - -/** - * Helper class featuring methods for Jedis connection handling, providing support for exception translation. Deprecated - * in favor of {@link JedisConverters} - * - * @author Costin Leau - * @author Jennifer Hickey - */ -@Deprecated -public abstract class JedisUtils { - - private static final String OK_CODE = "OK"; - private static final String OK_MULTI_CODE = "+OK"; - private static final byte[] ONE = new byte[] { '1' }; - private static final byte[] ZERO = new byte[] { '0' }; - - /** - * Converts the given, native Jedis exception to Spring's DAO hierarchy. - * - * @param ex Jedis exception - * @return converted exception - */ - public static DataAccessException convertJedisAccessException(JedisException ex) { - if (ex instanceof JedisDataException) { - return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); - } - if (ex instanceof JedisConnectionException) { - return new RedisConnectionFailureException(ex.getMessage(), ex); - } - - // fallback to invalid data exception - return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); - } - - /** - * Converts the given, native, runtime Jedis exception to Spring's DAO hierarchy. - * - * @param ex Jedis runtime/unchecked exception - * @return converted exception - */ - public static DataAccessException convertJedisAccessException(RuntimeException ex) { - if (ex instanceof JedisException) { - return convertJedisAccessException((JedisException) ex); - } - - return null; - } - - static DataAccessException convertJedisAccessException(IOException ex) { - if (ex instanceof UnknownHostException) { - return new RedisConnectionFailureException("Unknown host " + ex.getMessage(), ex); - } - return new RedisConnectionFailureException("Could not connect to Redis server", ex); - } - - static DataAccessException convertJedisAccessException(TimeoutException ex) { - throw new RedisConnectionFailureException("Jedis pool timed out. Could not get Redis Connection", ex); - } - - static boolean isStatusOk(String status) { - return status != null && (OK_CODE.equals(status) || OK_MULTI_CODE.equals(status)); - } - - /** - * Deprecated. Use #{@link JedisConverters#toBoolean(Long)} - */ - @Deprecated - static Boolean convertCodeReply(Number code) { - return (code != null ? code.intValue() == 1 : null); - } - - /** - * Deprecated. Use #{@link JedisConverters#toTupleSet(Set)} - */ - @Deprecated - static Set convertJedisTuple(Set tuples) { - Set value = new LinkedHashSet<>(tuples.size()); - for (redis.clients.jedis.Tuple tuple : tuples) { - value.add(new DefaultTuple(tuple.getBinaryElement(), tuple.getScore())); - } - - return value; - } - - static byte[][] convert(Map hgetAll) { - byte[][] result = new byte[hgetAll.size() * 2][]; - - int index = 0; - for (Map.Entry entry : hgetAll.entrySet()) { - result[index++] = entry.getKey(); - result[index++] = entry.getValue(); - } - return result; - } - - /** - * Deprecated. Implement a method in {@link JedisConverters} instead - */ - @Deprecated - static Map convert(String[] fields, String[] values) { - Map result = new LinkedHashMap<>(fields.length); - - for (int i = 0; i < values.length; i++) { - result.put(fields[i], values[i]); - } - return result; - } - - /** - * Deprecated. Implement a method in {@link JedisConverters} instead - */ - @Deprecated - static String[] arrange(String[] keys, String[] values) { - String[] result = new String[keys.length * 2]; - - for (int i = 0; i < keys.length; i++) { - int index = i << 1; - result[index] = keys[i]; - result[index + 1] = values[i]; - - } - return result; - } - - static SortingParams convertSortParams(SortParameters params) { - SortingParams jedisParams = null; - - if (params != null) { - jedisParams = new SortingParams(); - - byte[] byPattern = params.getByPattern(); - if (byPattern != null) { - jedisParams.by(params.getByPattern()); - } - - byte[][] getPattern = params.getGetPattern(); - if (getPattern != null) { - jedisParams.get(getPattern); - } - - Range limit = params.getLimit(); - if (limit != null) { - jedisParams.limit((int) limit.getStart(), (int) limit.getCount()); - } - Order order = params.getOrder(); - if (order != null && order.equals(Order.DESC)) { - jedisParams.desc(); - } - Boolean isAlpha = params.isAlphabetic(); - if (isAlpha != null && isAlpha) { - jedisParams.alpha(); - } - } - - return jedisParams; - } - - /** - * Deprecated. Use #{@link JedisConverters#toBit(Boolean)} - */ - @Deprecated - static byte[] asBit(boolean value) { - return (value ? ONE : ZERO); - } - - static ListPosition convertPosition(Position where) { - Assert.notNull(where, "list positions are mandatory"); - return (Position.AFTER.equals(where) ? ListPosition.AFTER : ListPosition.BEFORE); - } - - /** - * Deprecated. Use #{@link JedisConverters#toProperties(String)} - */ - @Deprecated - static Properties info(String string) { - Properties info = new Properties(); - StringReader stringReader = new StringReader(string); - try { - info.load(stringReader); - } catch (Exception ex) { - throw new RedisSystemException("Cannot read Redis info", ex); - } finally { - stringReader.close(); - } - return info; - } - - static BinaryJedisPubSub adaptPubSub(MessageListener listener) { - return new JedisMessageListener(listener); - } - - /** - * Deprecated. Use #{@link JedisConverters#toStrings(byte[][])} - */ - @Deprecated - static String[] convert(byte[]... raw) { - String[] result = new String[raw.length]; - - for (int i = 0; i < raw.length; i++) { - result[i] = SafeEncoder.encode(raw[i]); - } - - return result; - } - - static byte[][] bXPopArgs(int timeout, byte[]... keys) { - List args = new ArrayList<>(); - for (byte[] arg : keys) { - args.add(arg); - } - args.add(Protocol.toByteArray(timeout)); - return args.toArray(new byte[args.size()][]); - } - - /** - * Deprecated. Use #{@link JedisConverters#toBytes(Integer)} - */ - @Deprecated - static byte[] asBytes(int number) { - return String.valueOf(number).getBytes(); - } - - /** - * Deprecated. Use #{@link JedisConverters#toString(byte[])} - */ - @Deprecated - static String asString(byte[] raw) { - return SafeEncoder.encode(raw); - } - - @SuppressWarnings("unchecked") - static Object convertScriptReturn(ReturnType returnType, Object result) { - if (result instanceof String) { - // evalsha converts byte[] to String. Convert back for consistency - return SafeEncoder.encode((String) result); - } - if (returnType == ReturnType.STATUS) { - return JedisUtils.asString((byte[]) result); - } - if (returnType == ReturnType.BOOLEAN) { - // Lua false comes back as a null bulk reply - if (result == null) { - return Boolean.FALSE; - } - return ((Long) result == 1); - } - if (returnType == ReturnType.MULTI) { - List resultList = (List) result; - List convertedResults = new ArrayList<>(); - for (Object res : resultList) { - if (res instanceof String) { - // evalsha converts byte[] to String. Convert back for consistency - convertedResults.add(SafeEncoder.encode((String) res)); - } else { - convertedResults.add(res); - } - } - return convertedResults; - } - return result; - } - -} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisVersionUtil.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisVersionUtil.java deleted file mode 100644 index 06149f6e88..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisVersionUtil.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2014-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 redis.clients.jedis.Jedis; - -import java.io.IOException; -import java.util.Properties; - -import org.springframework.core.io.support.PropertiesLoaderUtils; -import org.springframework.data.util.Version; -import org.springframework.util.StringUtils; - -/** - * @author Christoph Strobl - * @since 1.3 - */ -public class JedisVersionUtil { - - private static Version jedisVersion = parseVersion(resolveJedisVersion()); - - /** - * @return current {@link redis.clients.jedis.Jedis} version. - */ - public static Version jedisVersion() { - return jedisVersion; - } - - /** - * Parse version string {@literal eg. 1.1.1} to {@link Version}. - * - * @param version - * @return - */ - static Version parseVersion(String version) { - return Version.parse(version); - } - - /** - * @return true if used jedis version is at minimum {@literal 2.4}. - */ - public static boolean atLeastJedis24() { - return atLeast("2.4"); - } - - private static String resolveJedisVersion() { - - String version = Jedis.class.getPackage().getImplementationVersion(); - - if (!StringUtils.hasText(version)) { - try { - Properties props = PropertiesLoaderUtils.loadAllProperties("META-INF/maven/redis.clients/jedis/pom.properties"); - if (props.containsKey("version")) { - version = props.getProperty("version"); - } - } catch (IOException e) { - // ignore this one - } - } - return version; - } - - /** - * Compares given version string against current jedis version. - * - * @param version - * @return true in case given version is greater than equal to current one. - */ - public static boolean atLeast(String version) { - return jedisVersion.compareTo(parseVersion(version)) >= 0; - } - - /** - * Compares given version string against current jedis version. - * - * @param version - * @return true in case given version is less than equal to current one. - */ - public static boolean atMost(String version) { - return jedisVersion.compareTo(parseVersion(version)) <= 0; - } - -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 18325aa49a..1376b966de 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -51,7 +51,6 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Range.Boundary; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.convert.Converters; -import org.springframework.data.redis.connection.convert.LongToBooleanConverter; import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; import org.springframework.data.redis.connection.zset.DefaultTuple; import org.springframework.data.redis.connection.zset.Tuple; @@ -124,12 +123,16 @@ public static Converter>, List> scoredValuesToTu }; } + public static boolean toBoolean(long value) { + return value == 1; + } + /** * @return * @sice 1.3 */ public static Converter longToBooleanConverter() { - return LongToBooleanConverter.INSTANCE; + return Converters::toBoolean; } public static Long toLong(@Nullable Date source) { 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 15902f6577..6298a1b448 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 @@ -97,13 +97,13 @@ public Flux> renameNX(Publisher co return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null."); - Assert.notNull(command.getNewName(), "NewName must not be null!"); + Assert.notNull(command.getNewKey(), "NewName must not be null!"); - if (ClusterSlotHashUtil.isSameSlotForAllKeys(command.getKey(), command.getNewName())) { + if (ClusterSlotHashUtil.isSameSlotForAllKeys(command.getKey(), command.getNewKey())) { return super.renameNX(Mono.just(command)); } - Mono result = cmd.exists(command.getNewName()).flatMap(exists -> { + Mono result = cmd.exists(command.getNewKey()).flatMap(exists -> { if (exists == 1) { return Mono.just(Boolean.FALSE); @@ -112,8 +112,8 @@ public Flux> renameNX(Publisher co return cmd.dump(command.getKey()) .switchIfEmpty(Mono.error(new RedisSystemException("Cannot rename key that does not exist", new RedisException("ERR no such key.")))) - .flatMap(value -> cmd.restore(command.getNewName(), 0, value).flatMap(res -> cmd.del(command.getKey()))) - .map(LettuceConverters.longToBooleanConverter()::convert); + .flatMap(value -> cmd.restore(command.getNewKey(), 0, value).flatMap(res -> cmd.del(command.getKey()))) + .map(LettuceConverters::toBoolean); }); return result.map(val -> new BooleanResponse<>(command, val)); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java index e2fb09dc67..01c22986d8 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveKeyCommands.java @@ -142,9 +142,9 @@ public Flux> rename(Publisher comm return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null!"); - Assert.notNull(command.getNewName(), "New name must not be null!"); + Assert.notNull(command.getNewKey(), "New name must not be null!"); - return cmd.rename(command.getKey(), command.getNewName()).map(LettuceConverters::stringToBoolean) + return cmd.rename(command.getKey(), command.getNewKey()).map(LettuceConverters::stringToBoolean) .map(value -> new BooleanResponse<>(command, value)); })); } @@ -155,9 +155,9 @@ public Flux> renameNX(Publisher co return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null!"); - Assert.notNull(command.getNewName(), "New name must not be null!"); + Assert.notNull(command.getNewKey(), "New name must not be null!"); - return cmd.renamenx(command.getKey(), command.getNewName()).map(value -> new BooleanResponse<>(command, value)); + return cmd.renamenx(command.getKey(), command.getNewKey()).map(value -> new BooleanResponse<>(command, value)); })); } diff --git a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java index da6a56d0f8..f1eba8d4ba 100644 --- a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java +++ b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java @@ -191,7 +191,7 @@ byte[][] rawKeys(K key, K otherKey) { byte[][] rawKeys = new byte[2][]; rawKeys[0] = rawKey(key); - rawKeys[1] = rawKey(key); + rawKeys[1] = rawKey(otherKey); return rawKeys; } diff --git a/src/main/java/org/springframework/data/redis/core/BoundGeoOperations.java b/src/main/java/org/springframework/data/redis/core/BoundGeoOperations.java index 73c69f58a4..f2810a4f3c 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundGeoOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundGeoOperations.java @@ -52,21 +52,6 @@ public interface BoundGeoOperations extends BoundKeyOperations { @Nullable Long add(Point point, M member); - /** - * Add {@link Point} with given member {@literal name} to {@literal key}. - * - * @param point must not be {@literal null}. - * @param member must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(Point, Object)}. - */ - @Deprecated - @Nullable - default Long geoAdd(Point point, M member) { - return add(point, member); - } - /** * Add {@link GeoLocation} to {@literal key}. * @@ -78,20 +63,6 @@ default Long geoAdd(Point point, M member) { @Nullable Long add(GeoLocation location); - /** - * Add {@link GeoLocation} to {@literal key}. - * - * @param location must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(GeoLocation)}. - */ - @Deprecated - @Nullable - default Long geoAdd(GeoLocation location) { - return add(location); - } - /** * Add {@link Map} of member / {@link Point} pairs to {@literal key}. * @@ -103,20 +74,6 @@ default Long geoAdd(GeoLocation location) { @Nullable Long add(Map memberCoordinateMap); - /** - * Add {@link Map} of member / {@link Point} pairs to {@literal key}. - * - * @param memberCoordinateMap must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(Map)}. - */ - @Deprecated - @Nullable - default Long geoAdd(Map memberCoordinateMap) { - return add(memberCoordinateMap); - } - /** * Add {@link GeoLocation}s to {@literal key} * @@ -128,20 +85,6 @@ default Long geoAdd(Map memberCoordinateMap) { @Nullable Long add(Iterable> locations); - /** - * Add {@link GeoLocation}s to {@literal key} - * - * @param locations must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(Iterable)}. - */ - @Deprecated - @Nullable - default Long geoAdd(Iterable> locations) { - return add(locations); - } - /** * Get the {@link Distance} between {@literal member1} and {@literal member2}. * @@ -154,21 +97,6 @@ default Long geoAdd(Iterable> locations) { @Nullable Distance distance(M member1, M member2); - /** - * Get the {@link Distance} between {@literal member1} and {@literal member2}. - * - * @param member1 must not be {@literal null}. - * @param member2 must not be {@literal null}. - * @return can be {@literal null}. - * @see Redis Documentation: GEODIST - * @deprecated since 2.0, use {@link #distance(Object, Object)}. - */ - @Deprecated - @Nullable - default Distance geoDist(M member1, M member2) { - return distance(member1, member2); - } - /** * Get the {@link Distance} between {@literal member1} and {@literal member2} in the given {@link Metric}. * @@ -182,22 +110,6 @@ default Distance geoDist(M member1, M member2) { @Nullable Distance distance(M member1, M member2, Metric metric); - /** - * Get the {@link Distance} between {@literal member1} and {@literal member2} in the given {@link Metric}. - * - * @param member1 must not be {@literal null}. - * @param member2 must not be {@literal null}. - * @param metric must not be {@literal null}. - * @return can be {@literal null}. - * @see Redis Documentation: GEODIST - * @deprecated since 2.0, use {@link #distance(Object, Object, Metric)}. - */ - @Deprecated - @Nullable - default Distance geoDist(M member1, M member2, Metric metric) { - return distance(member1, member2, metric); - } - /** * Get Geohash representation of the position for one or more {@literal member}s. * @@ -209,20 +121,6 @@ default Distance geoDist(M member1, M member2, Metric metric) { @Nullable List hash(M... members); - /** - * Get Geohash representation of the position for one or more {@literal member}s. - * - * @param members must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEOHASH - * @deprecated since 2.0, use {@link #hash(Object[])}. - */ - @Deprecated - @Nullable - default List geoHash(M... members) { - return hash(members); - } - /** * Get the {@link Point} representation of positions for one or more {@literal member}s. * @@ -234,19 +132,6 @@ default List geoHash(M... members) { @Nullable List position(M... members); - /** - * Get the {@link Point} representation of positions for one or more {@literal member}s. - * - * @param members must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEOPOS - * @deprecated since 2.0, use {@link #position(Object[])}. - */ - @Deprecated - @Nullable - default List geoPos(M... members) { - return position(members); - } /** * Get the {@literal member}s within the boundaries of a given {@link Circle}. @@ -259,20 +144,6 @@ default List geoPos(M... members) { @Nullable GeoResults> radius(Circle within); - /** - * Get the {@literal member}s within the boundaries of a given {@link Circle}. - * - * @param within must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUS - * @deprecated since 2.0, use {@link #radius(Circle)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadius(Circle within) { - return radius(within); - } - /** * Get the {@literal member}s within the boundaries of a given {@link Circle} applying {@link GeoRadiusCommandArgs}. * @@ -285,23 +156,6 @@ default GeoResults> geoRadius(Circle within) { @Nullable GeoResults> radius(Circle within, GeoRadiusCommandArgs args); - /** - * Get the {@literal member}s within the boundaries of a given {@link Circle} applying {@link GeoRadiusCommandArgs}. - * - * @param within must not be {@literal null}. - * @param args must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUS - * @deprecated since 2.0, use {@link #radius(Circle, GeoRadiusCommandArgs)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadius(Circle within, GeoRadiusCommandArgs args) { - return radius(within, args); - } - - // TODO: Bound ops should not accept K key - /** * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given * {@literal radius}. @@ -313,23 +167,7 @@ default GeoResults> geoRadius(Circle within, GeoRadiusCommandArgs * @see Redis Documentation: GEORADIUSBYMEMBER */ @Nullable - GeoResults> radius(K key, M member, double radius); - - /** - * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given - * {@literal radius}. - * - * @param member must not be {@literal null}. - * @param radius - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUSBYMEMBER - * @deprecated since 2.0, use {@link #radius(Object, Object, double)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadiusByMember(K key, M member, double radius) { - return radius(key, member, radius); - } + GeoResults> radius(M member, double radius); /** * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given @@ -344,22 +182,6 @@ default GeoResults> geoRadiusByMember(K key, M member, double rad @Nullable GeoResults> radius(M member, Distance distance); - /** - * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given - * {@literal radius} applying {@link Metric}. - * - * @param member must not be {@literal null}. - * @param distance must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUSBYMEMBER - * @deprecated since 2.0, use {@link #radius(Object, Distance)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadiusByMember(M member, Distance distance) { - return radius(member, distance); - } - /** * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given * {@literal radius} applying {@link Metric} and {@link GeoRadiusCommandArgs}. @@ -374,23 +196,6 @@ default GeoResults> geoRadiusByMember(M member, Distance distance @Nullable GeoResults> radius(M member, Distance distance, GeoRadiusCommandArgs args); - /** - * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given - * {@literal radius} applying {@link Metric} and {@link GeoRadiusCommandArgs}. - * - * @param member must not be {@literal null}. - * @param distance must not be {@literal null}. - * @param args must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUSBYMEMBER - * @deprecated since 2.0, use {@link #radius(Object, Distance, GeoRadiusCommandArgs)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadiusByMember(M member, Distance distance, GeoRadiusCommandArgs args) { - return radius(member, distance, args); - } - /** * Remove the {@literal member}s. * @@ -401,19 +206,6 @@ default GeoResults> geoRadiusByMember(M member, Distance distance @Nullable Long remove(M... members); - /** - * Remove the {@literal member}s. - * - * @param members must not be {@literal null}. - * @return Number of elements removed. {@literal null} when used in pipeline / transaction. - * @deprecated since 2.0, use {@link #remove(Object[])}. - */ - @Deprecated - @Nullable - default Long geoRemove(M... members) { - return remove(members); - } - /** * Get the {@literal member}s within the boundaries of a given {@link Circle}. * diff --git a/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java b/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java index 46d98756b2..191ead24f7 100644 --- a/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java +++ b/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java @@ -31,8 +31,8 @@ */ public class ConvertingCursor implements Cursor { - private Cursor delegate; - private Converter converter; + private final Cursor delegate; + private final Converter converter; /** * @param cursor Cursor must not be {@literal null}. @@ -77,12 +77,6 @@ public boolean isClosed() { return delegate.isClosed(); } - @Override - public Cursor open() { - this.delegate = delegate.open(); - return this; - } - @Override public long getPosition() { return delegate.getPosition(); diff --git a/src/main/java/org/springframework/data/redis/core/Cursor.java b/src/main/java/org/springframework/data/redis/core/Cursor.java index ab27df8cd5..9f865303c1 100644 --- a/src/main/java/org/springframework/data/redis/core/Cursor.java +++ b/src/main/java/org/springframework/data/redis/core/Cursor.java @@ -48,16 +48,6 @@ public interface Cursor extends CloseableIterator { */ boolean isClosed(); - /** - * Opens cursor and returns itself. This method is intended to be called by components constructing a {@link Cursor} - * and should not be called externally. - * - * @return the opened cursor. - * @deprecated to be removed from the interface in the next major version. - */ - @Deprecated - Cursor open(); - /** * @return the current position of the cursor. */ diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java index ad88d80251..d78ecd8451 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java @@ -105,7 +105,7 @@ public GeoResults> radius(Circle within, GeoRadiusCommandArgs par } @Override - public GeoResults> radius(K key, M member, double radius) { + public GeoResults> radius(M member, double radius) { return ops.radius(getKey(), member, radius); } diff --git a/src/main/java/org/springframework/data/redis/core/GeoOperations.java b/src/main/java/org/springframework/data/redis/core/GeoOperations.java index 27af3a8051..88b0b9e64c 100644 --- a/src/main/java/org/springframework/data/redis/core/GeoOperations.java +++ b/src/main/java/org/springframework/data/redis/core/GeoOperations.java @@ -56,22 +56,6 @@ public interface GeoOperations { @Nullable Long add(K key, Point point, M member); - /** - * Add {@link Point} with given member {@literal name} to {@literal key}. - * - * @param key must not be {@literal null}. - * @param point must not be {@literal null}. - * @param member must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(Object, Point, Object)}. - */ - @Deprecated - @Nullable - default Long geoAdd(K key, Point point, M member) { - return add(key, point, member); - } - /** * Add {@link GeoLocation} to {@literal key}. * @@ -84,21 +68,6 @@ default Long geoAdd(K key, Point point, M member) { @Nullable Long add(K key, GeoLocation location); - /** - * Add {@link GeoLocation} to {@literal key}. - * - * @param key must not be {@literal null}. - * @param location must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(Object, GeoLocation)}. - */ - @Deprecated - @Nullable - default Long geoAdd(K key, GeoLocation location) { - return add(key, location); - } - /** * Add {@link Map} of member / {@link Point} pairs to {@literal key}. * @@ -111,21 +80,6 @@ default Long geoAdd(K key, GeoLocation location) { @Nullable Long add(K key, Map memberCoordinateMap); - /** - * Add {@link Map} of member / {@link Point} pairs to {@literal key}. - * - * @param key must not be {@literal null}. - * @param memberCoordinateMap must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(Object, Map)}. - */ - @Deprecated - @Nullable - default Long geoAdd(K key, Map memberCoordinateMap) { - return add(key, memberCoordinateMap); - } - /** * Add {@link GeoLocation}s to {@literal key} * @@ -138,21 +92,6 @@ default Long geoAdd(K key, Map memberCoordinateMap) { @Nullable Long add(K key, Iterable> locations); - /** - * Add {@link GeoLocation}s to {@literal key} - * - * @param key must not be {@literal null}. - * @param locations must not be {@literal null}. - * @return Number of elements added. {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: GEOADD - * @deprecated since 2.0, use {@link #add(Object, Iterable)}. - */ - @Deprecated - @Nullable - default Long geoAdd(K key, Iterable> locations) { - return add(key, locations); - } - /** * Get the {@link Distance} between {@literal member1} and {@literal member2}. * @@ -166,22 +105,6 @@ default Long geoAdd(K key, Iterable> locations) { @Nullable Distance distance(K key, M member1, M member2); - /** - * Get the {@link Distance} between {@literal member1} and {@literal member2}. - * - * @param key must not be {@literal null}. - * @param member1 must not be {@literal null}. - * @param member2 must not be {@literal null}. - * @return can be {@literal null}. - * @see Redis Documentation: GEODIST - * @deprecated since 2.0, use {@link #distance(Object, Object, Object)}. - */ - @Deprecated - @Nullable - default Distance geoDist(K key, M member1, M member2) { - return distance(key, member1, member2); - } - /** * Get the {@link Distance} between {@literal member1} and {@literal member2} in the given {@link Metric}. * @@ -196,23 +119,6 @@ default Distance geoDist(K key, M member1, M member2) { @Nullable Distance distance(K key, M member1, M member2, Metric metric); - /** - * Get the {@link Distance} between {@literal member1} and {@literal member2} in the given {@link Metric}. - * - * @param key must not be {@literal null}. - * @param member1 must not be {@literal null}. - * @param member2 must not be {@literal null}. - * @param metric must not be {@literal null}. - * @return can be {@literal null}. - * @see Redis Documentation: GEODIST - * @deprecated since 2.0, use {@link #distance(Object, Object, Object, Metric)}. - */ - @Deprecated - @Nullable - default Distance geoDist(K key, M member1, M member2, Metric metric) { - return distance(key, member1, member2, metric); - } - /** * Get Geohash representation of the position for one or more {@literal member}s. * @@ -225,21 +131,6 @@ default Distance geoDist(K key, M member1, M member2, Metric metric) { @Nullable List hash(K key, M... members); - /** - * Get Geohash representation of the position for one or more {@literal member}s. - * - * @param key must not be {@literal null}. - * @param members must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEOHASH - * @deprecated since 2.0, use {@link #hash(Object, Object[])}. - */ - @Deprecated - @Nullable - default List geoHash(K key, M... members) { - return hash(key, members); - } - /** * Get the {@link Point} representation of positions for one or more {@literal member}s. * @@ -252,21 +143,6 @@ default List geoHash(K key, M... members) { @Nullable List position(K key, M... members); - /** - * Get the {@link Point} representation of positions for one or more {@literal member}s. - * - * @param key must not be {@literal null}. - * @param members must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEOPOS - * @deprecated since 2.0, use {@link #position(Object, Object[])}. - */ - @Deprecated - @Nullable - default List geoPos(K key, M... members) { - return position(key, members); - } - /** * Get the {@literal member}s within the boundaries of a given {@link Circle}. * @@ -279,21 +155,6 @@ default List geoPos(K key, M... members) { @Nullable GeoResults> radius(K key, Circle within); - /** - * Get the {@literal member}s within the boundaries of a given {@link Circle}. - * - * @param key must not be {@literal null}. - * @param within must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUS - * @deprecated since 2.0, use {@link #radius(Object, Circle)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadius(K key, Circle within) { - return radius(key, within); - } - /** * Get the {@literal member}s within the boundaries of a given {@link Circle} applying {@link GeoRadiusCommandArgs}. * @@ -307,22 +168,6 @@ default GeoResults> geoRadius(K key, Circle within) { @Nullable GeoResults> radius(K key, Circle within, GeoRadiusCommandArgs args); - /** - * Get the {@literal member}s within the boundaries of a given {@link Circle} applying {@link GeoRadiusCommandArgs}. - * - * @param key must not be {@literal null}. - * @param within must not be {@literal null}. - * @param args must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUS - * @deprecated since 2.0, use {@link #radius(Object, Circle, GeoRadiusCommandArgs)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadius(K key, Circle within, GeoRadiusCommandArgs args) { - return radius(key, within, args); - } - /** * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given * {@literal radius}. @@ -337,23 +182,6 @@ default GeoResults> geoRadius(K key, Circle within, GeoRadiusComm @Nullable GeoResults> radius(K key, M member, double radius); - /** - * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given - * {@literal radius}. - * - * @param key must not be {@literal null}. - * @param member must not be {@literal null}. - * @param radius - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUSBYMEMBER - * @deprecated since 2.0, use {@link #radius(Object, Object, double)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadiusByMember(K key, M member, double radius) { - return radius(key, member, radius); - } - /** * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given * {@literal radius} applying {@link Metric}. @@ -368,23 +196,6 @@ default GeoResults> geoRadiusByMember(K key, M member, double rad @Nullable GeoResults> radius(K key, M member, Distance distance); - /** - * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given - * {@literal radius} applying {@link Metric}. - * - * @param key must not be {@literal null}. - * @param member must not be {@literal null}. - * @param distance must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUSBYMEMBER - * @deprecated since 2.0, use {@link #radius(Object, Object, Distance)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadiusByMember(K key, M member, Distance distance) { - return radius(key, member, distance); - } - /** * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given * {@literal radius} applying {@link Metric} and {@link GeoRadiusCommandArgs}. @@ -400,24 +211,6 @@ default GeoResults> geoRadiusByMember(K key, M member, Distance d @Nullable GeoResults> radius(K key, M member, Distance distance, GeoRadiusCommandArgs args); - /** - * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given - * {@literal radius} applying {@link Metric} and {@link GeoRadiusCommandArgs}. - * - * @param key must not be {@literal null}. - * @param member must not be {@literal null}. - * @param distance must not be {@literal null}. - * @param args must not be {@literal null}. - * @return never {@literal null} unless used in pipeline / transaction. - * @see Redis Documentation: GEORADIUSBYMEMBER - * @deprecated since 2.0, use {@link #radius(Object, Object, Distance, GeoRadiusCommandArgs)}. - */ - @Deprecated - @Nullable - default GeoResults> geoRadiusByMember(K key, M member, Distance distance, GeoRadiusCommandArgs args) { - return radius(key, member, distance, args); - } - /** * Remove the {@literal member}s. * @@ -429,20 +222,6 @@ default GeoResults> geoRadiusByMember(K key, M member, Distance d @Nullable Long remove(K key, M... members); - /** - * Remove the {@literal member}s. - * - * @param key must not be {@literal null}. - * @param members must not be {@literal null}. - * @return Number of elements removed. {@literal null} when used in pipeline / transaction. - * @deprecated since 2.0, use {@link #remove(Object, Object[])}. - */ - @Deprecated - @Nullable - default Long geoRemove(K key, M... members) { - return remove(key, members); - } - /** * Get the {@literal member}s within the boundaries of a given {@link Circle}. * diff --git a/src/main/java/org/springframework/data/redis/core/RedisCommand.java b/src/main/java/org/springframework/data/redis/core/RedisCommand.java index fb69f2c6e4..4e959adaf1 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisCommand.java +++ b/src/main/java/org/springframework/data/redis/core/RedisCommand.java @@ -141,8 +141,6 @@ public enum RedisCommand { // -- R RANDOMKEY("r", 0, 0), // - @Deprecated - RANAME("w", 2, 2), // RENAME("w", 2, 2), // RENAMENX("w", 2, 2), // REPLICAOF("w", 2), // diff --git a/src/main/java/org/springframework/data/redis/core/RedisConnectionUtils.java b/src/main/java/org/springframework/data/redis/core/RedisConnectionUtils.java index 08d38d552e..6970ba0e70 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisConnectionUtils.java +++ b/src/main/java/org/springframework/data/redis/core/RedisConnectionUtils.java @@ -267,22 +267,6 @@ public static void releaseConnection(@Nullable RedisConnection conn, RedisConnec doCloseConnection(conn); } - /** - * Closes the given {@link RedisConnection}, created via the given factory if not managed externally (i.e. not bound - * to the transaction). - * - * @param conn the Redis connection to close. - * @param factory the Redis factory that the connection was created with. - * @param transactionSupport whether transaction support is enabled. - * @since 2.1.9 - * @deprecated since 2.4.2, use {@link #releaseConnection(RedisConnection, RedisConnectionFactory)} - */ - @Deprecated - public static void releaseConnection(@Nullable RedisConnection conn, RedisConnectionFactory factory, - boolean transactionSupport) { - releaseConnection(conn, factory); - } - /** * Determine whether the given two RedisConnections are equal, asking the target {@link RedisConnection} in case of a * proxy. Used to detect equality even if the user passed in a raw target Connection while the held one is a proxy. diff --git a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java index be3e237e7d..922a3523d7 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java +++ b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java @@ -44,7 +44,6 @@ import org.springframework.data.redis.core.PartialUpdate.PropertyUpdate; import org.springframework.data.redis.core.PartialUpdate.UpdateCommand; import org.springframework.data.redis.core.RedisKeyValueAdapter.RedisUpdateObject.Index; -import org.springframework.data.redis.core.convert.CustomConversions; import org.springframework.data.redis.core.convert.GeoIndexedPropertyValue; import org.springframework.data.redis.core.convert.KeyspaceConfiguration; import org.springframework.data.redis.core.convert.MappingRedisConverter; @@ -140,21 +139,6 @@ public RedisKeyValueAdapter(RedisOperations redisOps, RedisMappingContext this(redisOps, mappingContext, new RedisCustomConversions()); } - /** - * Creates new {@link RedisKeyValueAdapter}. - * - * @param redisOps must not be {@literal null}. - * @param mappingContext must not be {@literal null}. - * @param customConversions can be {@literal null}. - * @deprecated since 2.0, use - * {@link #RedisKeyValueAdapter(RedisOperations, RedisMappingContext, org.springframework.data.convert.CustomConversions)}. - */ - @Deprecated - public RedisKeyValueAdapter(RedisOperations redisOps, RedisMappingContext mappingContext, - CustomConversions customConversions) { - this(redisOps, mappingContext, (org.springframework.data.convert.CustomConversions) customConversions); - } - /** * Creates new {@link RedisKeyValueAdapter}. * diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 1ddc971e9d..cc9b4af92c 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -222,7 +222,7 @@ public T execute(RedisCallback action, boolean exposeConnection, boolean return postProcessResult(result, connToUse, existingConnection); } finally { - RedisConnectionUtils.releaseConnection(conn, factory, enableTransactionSupport); + RedisConnectionUtils.releaseConnection(conn, factory); } } diff --git a/src/main/java/org/springframework/data/redis/core/convert/CustomConversions.java b/src/main/java/org/springframework/data/redis/core/convert/CustomConversions.java deleted file mode 100644 index d132bb7aef..0000000000 --- a/src/main/java/org/springframework/data/redis/core/convert/CustomConversions.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011-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.core.convert; - -import java.util.List; - -/** - * Value object to capture custom conversion. That is essentially a {@link List} of converters and some additional logic - * around them. - * - * @author Olivyer Gierke - * @author Thomas Darimont - * @author Christoph Strobl - * @author Mark Paluch - * @since 1.7 - * @deprecated since 2.0, use {@link RedisCustomConversions}. - */ -@Deprecated -public class CustomConversions extends RedisCustomConversions { - - /** - * Creates an empty {@link CustomConversions} object. - */ - public CustomConversions() {} - - /** - * Creates a new {@link CustomConversions} instance registering the given converters. - * - * @param converters - */ - public CustomConversions(List converters) { - super(converters); - } -} diff --git a/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java b/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java index 1697c854f7..8233e34968 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java +++ b/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java @@ -1195,12 +1195,6 @@ public static class KeyspaceIdentifier { public static final String DELIMITER = ":"; public static final String PHANTOM_SUFFIX = DELIMITER + PHANTOM; - /** - * @deprecated since 2.6. Please use {@link #DELIMITER} instead. - */ - @Deprecated(/* since="2.6" */) - public static final String DELIMITTER = DELIMITER; - private final String keyspace; private final String id; private final boolean phantomKey; @@ -1281,12 +1275,6 @@ public static class BinaryKeyspaceIdentifier { public static final byte DELIMITER = ':'; public static final byte[] PHANTOM_SUFFIX = ByteUtils.concat(new byte[] { DELIMITER }, PHANTOM); - /** - * @deprecated since 2.6. Please use {@link #DELIMITER} instead. - */ - @Deprecated(/* since="2.6" */) - public static final byte DELIMITTER = DELIMITER; - private final byte[] keyspace; private final byte[] id; private final boolean phantomKey; diff --git a/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java b/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java index 5ad27fcff8..c0264d796e 100644 --- a/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java +++ b/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java @@ -19,7 +19,7 @@ import java.util.Map; import java.util.Set; -import org.springframework.data.redis.core.convert.CustomConversions; +import org.springframework.data.convert.CustomConversions; import org.springframework.data.redis.core.convert.IndexResolver; import org.springframework.data.redis.core.convert.IndexedData; import org.springframework.data.redis.core.convert.MappingRedisConverter; @@ -95,24 +95,13 @@ public ObjectHashMapper(RedisConverter converter) { this.converter = converter; } - /** - * Creates new {@link ObjectHashMapper}. - * - * @param customConversions can be {@literal null}. - * @deprecated since 2.0, use {@link #ObjectHashMapper(org.springframework.data.convert.CustomConversions)}. - */ - @Deprecated - public ObjectHashMapper(CustomConversions customConversions) { - this((org.springframework.data.convert.CustomConversions) customConversions); - } - /** * Creates new {@link ObjectHashMapper}. * * @param customConversions can be {@literal null}. * @since 2.0 */ - public ObjectHashMapper(@Nullable org.springframework.data.convert.CustomConversions customConversions) { + public ObjectHashMapper(@Nullable CustomConversions customConversions) { MappingRedisConverter mappingConverter = new MappingRedisConverter(new RedisMappingContext(), new NoOpIndexResolver(), new NoOpReferenceResolver()); diff --git a/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java b/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java index f48d36f194..62a9efa775 100644 --- a/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java +++ b/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java @@ -316,15 +316,6 @@ public Consumer getConsumer() { return consumer; } - /** - * @return - * @deprecated since 2.3, use {@link #isAutoAcknowledge()} for improved readability instead. - */ - @Deprecated - public boolean isAutoAck() { - return isAutoAcknowledge(); - } - /** * @return * @since 2.3 @@ -453,19 +444,6 @@ public ConsumerStreamReadRequestBuilder consumer(Consumer consumer) { return this; } - /** - * Configure auto-acknowledgement for stream message consumption. - * - * @param autoAck {@literal true} (default) to auto-acknowledge received messages or {@literal false} for external - * acknowledgement. - * @return {@code this} {@link ConsumerStreamReadRequestBuilder}. - * @deprecated since 2.3, use {@link #autoAcknowledge(boolean)} instead. - */ - @Deprecated - public ConsumerStreamReadRequestBuilder autoAck(boolean autoAck) { - return autoAcknowledge(autoAck); - } - /** * Configure auto-acknowledgement for stream message consumption. This method is an alias for * {@link #autoAck(boolean)} for improved readability. diff --git a/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java b/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java index 50d06397ae..f94122d328 100644 --- a/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java @@ -235,8 +235,8 @@ void executeCommandAsyncOnNodesShouldCompleteAndCollectErrorsOfAllNodes() { executor.executeCommandOnAllNodes(COMMAND_CALLBACK); } catch (ClusterCommandExecutionFailureException e) { - assertThat(e.getCauses().size()).isEqualTo(1); - assertThat(e.getCauses().iterator().next()).isInstanceOf(DataAccessException.class); + assertThat(e.getSuppressed()).hasSize(1); + assertThat(e.getSuppressed()[0]).isInstanceOf(DataAccessException.class); } verify(con1, times(1)).theWheelWeavesAsTheWheelWills(); diff --git a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java index 88252f9688..c4d9167226 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java @@ -161,10 +161,6 @@ public Boolean hSet(byte[] key, byte[] field, byte[] value) { return delegate.hSet(key, field, value); } - public void bgWriteAof() { - delegate.bgWriteAof(); - } - public Object execute(String command, byte[]... args) { return delegate.execute(command, args); } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryIntegrationTests.java index 86a8520288..73e04a75ba 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryIntegrationTests.java @@ -17,8 +17,6 @@ import static org.assertj.core.api.Assertions.*; -import redis.clients.jedis.JedisShardInfo; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -44,19 +42,6 @@ void tearDown() { } } - @Test // DATAREDIS-574 - void shardInfoShouldOverrideFactorySettings() { - - factory = new JedisConnectionFactory(new JedisShardInfo(SettingsUtils.getHost(), SettingsUtils.getPort())); - factory.setUsePool(false); - factory.setPassword("foo"); - factory.setHostName("bar"); - factory.setPort(1234); - factory.afterPropertiesSet(); - - assertThat(factory.getConnection().ping()).isEqualTo("PONG"); - } - @Test // DATAREDIS-574 void shouldInitializeWithStandaloneConfiguration() { diff --git a/src/test/java/org/springframework/data/redis/core/RedisConnectionUtilsUnitTests.java b/src/test/java/org/springframework/data/redis/core/RedisConnectionUtilsUnitTests.java index 889e27387d..433e7fc741 100644 --- a/src/test/java/org/springframework/data/redis/core/RedisConnectionUtilsUnitTests.java +++ b/src/test/java/org/springframework/data/redis/core/RedisConnectionUtilsUnitTests.java @@ -60,7 +60,7 @@ void shouldSilentlyCloseRedisConnection() { Mockito.reset(connectionMock1); doThrow(new IllegalStateException()).when(connectionMock1).close(); - RedisConnectionUtils.releaseConnection(connectionMock1, factoryMock, false); + RedisConnectionUtils.releaseConnection(connectionMock1, factoryMock); verify(connectionMock1).close(); } From 36f91ff42bfcfd9e0235cc8f13ac08c2bfe765c5 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 23 Feb 2022 14:22:49 +0100 Subject: [PATCH 06/12] Polishing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit StreamInfo subtypes now implement Streamable. Switch from stream mapping to for/each style to avoid Java Stream creation. Introduce getRequired(…) methods to improve nullability experience. --- .../connection/lettuce/StreamConverters.java | 14 +---- .../connection/stream/ByteBufferRecord.java | 26 ++++---- .../redis/connection/stream/ByteRecord.java | 16 ++--- .../redis/connection/stream/MapRecord.java | 6 +- .../data/redis/connection/stream/Record.java | 18 ++++++ .../redis/connection/stream/StreamInfo.java | 59 ++++++++++++------- .../connection/stream/StreamRecords.java | 12 ++-- .../stream/StreamSerialization.java | 23 +++++++- .../redis/connection/stream/StringRecord.java | 2 +- .../redis/core/ReactiveStreamOperations.java | 2 +- .../data/redis/core/StreamObjectMapper.java | 9 ++- .../data/redis/core/StreamOperations.java | 2 +- 12 files changed, 121 insertions(+), 68 deletions(-) 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 82ca4329a3..9e6e9df349 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 @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; -import java.util.stream.Collectors; import org.springframework.core.convert.converter.Converter; import org.springframework.data.redis.connection.RedisStreamCommands.XClaimOptions; @@ -38,6 +37,7 @@ import org.springframework.data.redis.connection.stream.StreamReadOptions; import org.springframework.data.redis.connection.stream.StreamRecords; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.lang.Nullable; import org.springframework.util.NumberUtils; /** @@ -69,7 +69,7 @@ class StreamConverters { return new org.springframework.data.redis.connection.stream.PendingMessage(id, consumer, Duration.ofMillis(it.getMsSinceLastDelivery()), it.getRedeliveryCount()); - }).collect(Collectors.toList()); + }).toList(); return new org.springframework.data.redis.connection.stream.PendingMessages(groupName, messages); @@ -111,18 +111,10 @@ static Converter, ByteRecord> byteRecordConverter( return (it) -> StreamRecords.newRecord().in(it.getStream()).withId(it.getId()).ofBytes(it.getBody()); } - static Converter>, List> byteRecordListConverter() { - return new ListConverter<>(byteRecordConverter()); - } - static Converter, RecordId> messageToIdConverter() { return (it) -> RecordId.of(it.getId()); } - static Converter>, List> messagesToIds() { - return MESSAGEs_TO_IDs; - } - /** * Convert the raw Lettuce xpending result to {@link PendingMessages}. * @@ -157,7 +149,7 @@ static PendingMessagesSummary toPendingMessagesInfo(String groupName, PendingMes * @param value dont't get me started om this. * @return preconverted values that Lettuce parsers are able to understand \ö/. */ - private static Object preConvertNativeValues(Object value) { + private static Object preConvertNativeValues(@Nullable Object value) { if (value instanceof ByteBuffer || value instanceof byte[]) { diff --git a/src/main/java/org/springframework/data/redis/connection/stream/ByteBufferRecord.java b/src/main/java/org/springframework/data/redis/connection/stream/ByteBufferRecord.java index 281ec32a00..fe1185d063 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/ByteBufferRecord.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/ByteBufferRecord.java @@ -17,8 +17,8 @@ import java.nio.ByteBuffer; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.stream.Collectors; import org.springframework.data.redis.hash.HashMapper; import org.springframework.data.redis.serializer.RedisSerializer; @@ -65,16 +65,17 @@ default MapRecord deserialize(@Nullable RedisSerializer serializ * @param valueSerializer can be {@literal null} if the values suite already the target format. * @return new {@link MapRecord} holding the deserialized values. */ - @SuppressWarnings({ "unchecked", "rawtypes" }) default MapRecord deserialize(@Nullable RedisSerializer streamSerializer, @Nullable RedisSerializer fieldSerializer, @Nullable RedisSerializer valueSerializer) { - return mapEntries(it -> Collections. singletonMap( - fieldSerializer != null ? fieldSerializer.deserialize(ByteUtils.getBytes(it.getKey())) : (HK) it.getKey(), - valueSerializer != null ? valueSerializer.deserialize(ByteUtils.getBytes(it.getValue())) : (HV) it.getValue()) - .entrySet().iterator().next()).withStreamKey( - streamSerializer != null ? streamSerializer.deserialize(ByteUtils.getBytes(getStream())) : (K) getStream()); + return mapEntries(it -> { + + Map map = Collections.singletonMap(StreamSerialization.deserialize(fieldSerializer, it.getKey()), + StreamSerialization.deserialize(valueSerializer, it.getValue())); + + return map.entrySet().iterator().next(); + }).withStreamKey(StreamSerialization.deserialize(streamSerializer, getRequiredStream())); } /** @@ -84,7 +85,7 @@ default MapRecord deserialize(@Nullable RedisSerializer source) { - return StreamRecords.newRecord().in(source.getStream()).withId(source.getId()).ofBuffer(source.getValue()); + return StreamRecords.newRecord().in(source.getRequiredStream()).withId(source.getId()).ofBuffer(source.getValue()); } /** @@ -97,10 +98,13 @@ static ByteBufferRecord of(MapRecord source) default ObjectRecord toObjectRecord( HashMapper mapper) { - Map targetMap = getValue().entrySet().stream().collect( - Collectors.toMap(entry -> ByteUtils.getBytes(entry.getKey()), entry -> ByteUtils.getBytes(entry.getValue()))); + Map value = getValue(); + Map targetMap = new LinkedHashMap<>(value.size()); + + value.forEach((k, v) -> targetMap.put(ByteUtils.getBytes(k), ByteUtils.getBytes(v))); return Record. of((OV) (mapper).fromHash((Map) targetMap)).withId(getId()) - .withStreamKey(getStream()); + .withStreamKey(getRequiredStream()); } + } diff --git a/src/main/java/org/springframework/data/redis/connection/stream/ByteRecord.java b/src/main/java/org/springframework/data/redis/connection/stream/ByteRecord.java index 18fb7d9cb9..f059363241 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/ByteRecord.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/ByteRecord.java @@ -16,8 +16,8 @@ package org.springframework.data.redis.connection.stream; import java.util.Collections; +import java.util.Map; -import org.springframework.data.redis.connection.RedisStreamCommands; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.lang.Nullable; @@ -65,11 +65,13 @@ default MapRecord deserialize(@Nullable RedisSerializer fieldSerializer, @Nullable RedisSerializer valueSerializer) { - return mapEntries(it -> Collections - . singletonMap(fieldSerializer != null ? fieldSerializer.deserialize(it.getKey()) : (HK) it.getKey(), - valueSerializer != null ? valueSerializer.deserialize(it.getValue()) : (HV) it.getValue()) - .entrySet().iterator().next()) - .withStreamKey(streamSerializer != null ? streamSerializer.deserialize(getStream()) : (K) getStream()); + return mapEntries(it -> { + + Map map = Collections.singletonMap(StreamSerialization.deserialize(fieldSerializer, it.getKey()), + StreamSerialization.deserialize(valueSerializer, it.getValue())); + + return map.entrySet().iterator().next(); + }).withStreamKey(StreamSerialization.deserialize(streamSerializer, getRequiredStream())); } /** @@ -79,6 +81,6 @@ default MapRecord deserialize(@Nullable RedisSerializer source) { - return StreamRecords.newRecord().in(source.getStream()).withId(source.getId()).ofBytes(source.getValue()); + return StreamRecords.newRecord().in(source.getRequiredStream()).withId(source.getId()).ofBytes(source.getValue()); } } diff --git a/src/main/java/org/springframework/data/redis/connection/stream/MapRecord.java b/src/main/java/org/springframework/data/redis/connection/stream/MapRecord.java index 9f9d62cf2a..4f95133247 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/MapRecord.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/MapRecord.java @@ -78,7 +78,7 @@ default MapRecord mapEntries(Function, Entry streamSerializ StreamSerialization.serialize(valueSerializer, it.getValue())).entrySet().iterator().next()); return StreamRecords.newRecord() // - .in(streamSerializer != null ? streamSerializer.serialize(getStream()) : (byte[]) getStream()) // + .in(StreamSerialization.serialize(streamSerializer, getRequiredStream())) // .withId(getId()) // .ofBytes(binaryMap.getValue()); } @@ -136,6 +136,6 @@ default ByteRecord serialize(@Nullable RedisSerializer streamSerializ */ @SuppressWarnings({ "unchecked", "rawtypes" }) default ObjectRecord toObjectRecord(HashMapper mapper) { - return Record. of((OV) mapper.fromHash((Map) getValue())).withId(getId()).withStreamKey(getStream()); + return Record. of((OV) mapper.fromHash((Map) getValue())).withId(getId()).withStreamKey(getRequiredStream()); } } diff --git a/src/main/java/org/springframework/data/redis/connection/stream/Record.java b/src/main/java/org/springframework/data/redis/connection/stream/Record.java index a6556707b3..9314902635 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/Record.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/Record.java @@ -39,6 +39,24 @@ public interface Record { @Nullable S getStream(); + /** + * The id of the stream (aka the {@literal key} in Redis). + * + * @return can be {@literal null}. + * @throws IllegalStateException if the stream is {@literal null}. + * @since 3.0 + */ + default S getRequiredStream() { + + S stream = getStream(); + + if (stream == null) { + throw new IllegalStateException("Stream is not available"); + } + + return stream; + } + /** * The id of the entry inside the stream. * diff --git a/src/main/java/org/springframework/data/redis/connection/stream/StreamInfo.java b/src/main/java/org/springframework/data/redis/connection/stream/StreamInfo.java index b181bccbb4..57b93a9d7f 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/StreamInfo.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/StreamInfo.java @@ -27,6 +27,7 @@ import java.util.stream.Stream; import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.util.Streamable; import org.springframework.lang.Nullable; /** @@ -67,6 +68,16 @@ T get(String entry, Class type) { return value == null ? null : type.cast(value); } + T getRequired(String entry, Class type) { + + T value = get(entry, type); + + if (value == null) { + throw new IllegalStateException("Value for entry '%s' is null.".formatted(entry)); + } + return value; + } + @Nullable T getAndMap(String entry, Class type, Function f) { @@ -124,8 +135,8 @@ public static XInfoStream fromList(List source) { * * @return */ - public Long streamLength() { - return get("length", Long.class); + public long streamLength() { + return getRequired("length", Long.class); } /** @@ -133,8 +144,8 @@ public Long streamLength() { * * @return */ - public Long radixTreeKeySize() { - return get("radix-tree-keys", Long.class); + public long radixTreeKeySize() { + return getRequired("radix-tree-keys", Long.class); } /** @@ -142,8 +153,8 @@ public Long radixTreeKeySize() { * * @return */ - public Long radixTreeNodesSize() { - return get("radix-tree-nodes", Long.class); + public long radixTreeNodesSize() { + return getRequired("radix-tree-nodes", Long.class); } /** @@ -151,8 +162,8 @@ public Long radixTreeNodesSize() { * * @return */ - public Long groupCount() { - return get("groups", Long.class); + public long groupCount() { + return getRequired("groups", Long.class); } /** @@ -162,7 +173,7 @@ public Long groupCount() { * @return */ public String lastGeneratedId() { - return get("last-generated-id", String.class); + return getRequired("last-generated-id", String.class); } /** @@ -209,7 +220,7 @@ public Map getLastEntry() { * * @author Christoph Strobl */ - public static class XInfoGroups { + public static class XInfoGroups implements Streamable { private final List groupInfoList; @@ -253,6 +264,7 @@ public int size() { /** * @return {@literal true} if no groups associated. */ + @Override public boolean isEmpty() { return groupInfoList.isEmpty(); } @@ -262,6 +274,7 @@ public boolean isEmpty() { * * @return */ + @Override public Iterator iterator() { return groupInfoList.iterator(); } @@ -281,6 +294,7 @@ public XInfoGroup get(int index) { * * @return */ + @Override public Stream stream() { return groupInfoList.stream(); } @@ -290,6 +304,7 @@ public Stream stream() { * * @param action */ + @Override public void forEach(Consumer action) { groupInfoList.forEach(action); } @@ -317,7 +332,7 @@ public static XInfoGroup fromList(List raw) { * @return */ public String groupName() { - return get("name", String.class); + return getRequired("name", String.class); } /** @@ -326,7 +341,7 @@ public String groupName() { * @return */ public Long consumerCount() { - return get("consumers", Long.class); + return getRequired("consumers", Long.class); } /** @@ -335,7 +350,7 @@ public Long consumerCount() { * @return */ public Long pendingCount() { - return get("pending", Long.class); + return getRequired("pending", Long.class); } /** @@ -344,11 +359,11 @@ public Long pendingCount() { * @return */ public String lastDeliveredId() { - return get("last-delivered-id", String.class); + return getRequired("last-delivered-id", String.class); } } - public static class XInfoConsumers { + public static class XInfoConsumers implements Streamable { private final List consumerInfoList; @@ -386,6 +401,7 @@ public int size() { /** * @return {@literal true} if no groups associated. */ + @Override public boolean isEmpty() { return consumerInfoList.isEmpty(); } @@ -395,6 +411,7 @@ public boolean isEmpty() { * * @return */ + @Override public Iterator iterator() { return consumerInfoList.iterator(); } @@ -414,6 +431,7 @@ public XInfoConsumer get(int index) { * * @return */ + @Override public Stream stream() { return consumerInfoList.stream(); } @@ -423,6 +441,7 @@ public Stream stream() { * * @param action */ + @Override public void forEach(Consumer action) { consumerInfoList.forEach(action); } @@ -458,7 +477,7 @@ public String groupName() { * @return */ public String consumerName() { - return get("name", String.class); + return getRequired("name", String.class); } /** @@ -466,8 +485,8 @@ public String consumerName() { * * @return */ - public Long idleTimeMs() { - return get("idle", Long.class); + public long idleTimeMs() { + return getRequired("idle", Long.class); } /** @@ -484,8 +503,8 @@ public Duration idleTime() { * * @return */ - public Long pendingCount() { - return get("pending", Long.class); + public long pendingCount() { + return getRequired("pending", Long.class); } } } diff --git a/src/main/java/org/springframework/data/redis/connection/stream/StreamRecords.java b/src/main/java/org/springframework/data/redis/connection/stream/StreamRecords.java index 6b6dcf7dd0..bf6f8cbcd1 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/StreamRecords.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/StreamRecords.java @@ -232,8 +232,8 @@ public ByteBufferRecord ofBuffer(Map value) { */ static class MapBackedRecord implements MapRecord { - private @Nullable S stream; - private RecordId recordId; + private final @Nullable S stream; + private final RecordId recordId; private final Map kvMap; MapBackedRecord(@Nullable S stream, RecordId recordId, Map kvMap) { @@ -249,7 +249,6 @@ public S getStream() { return stream; } - @Nullable @Override public RecordId getId() { return recordId; @@ -322,7 +321,7 @@ public int hashCode() { */ static class ByteMapBackedRecord extends MapBackedRecord implements ByteRecord { - ByteMapBackedRecord(byte[] stream, RecordId recordId, Map map) { + ByteMapBackedRecord(@Nullable byte[] stream, RecordId recordId, Map map) { super(stream, recordId, map); } @@ -343,7 +342,8 @@ public ByteMapBackedRecord withId(RecordId id) { static class ByteBufferMapBackedRecord extends MapBackedRecord implements ByteBufferRecord { - ByteBufferMapBackedRecord(ByteBuffer stream, RecordId recordId, Map map) { + ByteBufferMapBackedRecord(@Nullable ByteBuffer stream, @Nullable RecordId recordId, + Map map) { super(stream, recordId, map); } @@ -363,7 +363,7 @@ public ByteBufferMapBackedRecord withId(RecordId id) { */ static class StringMapBackedRecord extends MapBackedRecord implements StringRecord { - StringMapBackedRecord(String stream, RecordId recordId, Map stringStringMap) { + StringMapBackedRecord(@Nullable String stream, @Nullable RecordId recordId, Map stringStringMap) { super(stream, recordId, stringStringMap); } diff --git a/src/main/java/org/springframework/data/redis/connection/stream/StreamSerialization.java b/src/main/java/org/springframework/data/redis/connection/stream/StreamSerialization.java index 3f04237d45..938d63d598 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/StreamSerialization.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/StreamSerialization.java @@ -15,7 +15,10 @@ */ package org.springframework.data.redis.connection.stream; +import java.nio.ByteBuffer; + import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.util.ByteUtils; import org.springframework.lang.Nullable; /** @@ -34,11 +37,27 @@ class StreamSerialization { * @param value the value to serialize. * @return the serialized (binary) representation of {@code value}. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) static byte[] serialize(@Nullable RedisSerializer serializer, Object value) { return canSerialize(serializer, value) ? ((RedisSerializer) serializer).serialize(value) : (byte[]) value; } + /** + * Deserialize the {@code value using the optional {@link RedisSerializer}. If no conversion is possible, return + * {@code value}. @param serializer @param value @param @return + */ + static T deserialize(@Nullable RedisSerializer serializer, ByteBuffer value) { + return deserialize(serializer, ByteUtils.getBytes(value)); + } + + /** + * Deserialize the {@code value using the optional {@link RedisSerializer}. If no conversion is possible, return + * {@code value}. @param serializer @param value @param @return + */ + static T deserialize(@Nullable RedisSerializer serializer, byte[] value) { + return serializer != null ? serializer.deserialize(value) : (T) value; + } + /** * Returns whether the given {@link RedisSerializer} is capable of serializing the {@code value} to {@literal byte[]}. * @@ -47,7 +66,7 @@ static byte[] serialize(@Nullable RedisSerializer serializer, Object value) { * @return {@literal true} if the given {@link RedisSerializer} is capable of serializing the {@code value} to * {@literal byte[]}. */ - private static boolean canSerialize(@Nullable RedisSerializer serializer, Object value) { + private static boolean canSerialize(@Nullable RedisSerializer serializer, @Nullable Object value) { return serializer != null && (value == null || serializer.canSerialize(value.getClass())); } } diff --git a/src/main/java/org/springframework/data/redis/connection/stream/StringRecord.java b/src/main/java/org/springframework/data/redis/connection/stream/StringRecord.java index a7d08c3c4b..1df2f15853 100644 --- a/src/main/java/org/springframework/data/redis/connection/stream/StringRecord.java +++ b/src/main/java/org/springframework/data/redis/connection/stream/StringRecord.java @@ -41,6 +41,6 @@ public interface StringRecord extends MapRecord { * @return new instance of {@link StringRecord}. */ static StringRecord of(MapRecord source) { - return StreamRecords.newRecord().in(source.getStream()).withId(source.getId()).ofStrings(source.getValue()); + return StreamRecords.newRecord().in(source.getRequiredStream()).withId(source.getId()).ofStrings(source.getValue()); } } diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java index ff6e662f3c..c265e63dae 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveStreamOperations.java @@ -77,7 +77,7 @@ default Mono acknowledge(K key, String group, String... recordIds) { * @see Redis Documentation: XACK */ default Mono acknowledge(String group, Record record) { - return acknowledge(record.getStream(), group, record.getId()); + return acknowledge(record.getRequiredStream(), group, record.getId()); } /** diff --git a/src/main/java/org/springframework/data/redis/core/StreamObjectMapper.java b/src/main/java/org/springframework/data/redis/core/StreamObjectMapper.java index 0a7b2d6b1f..8cbfb035e7 100644 --- a/src/main/java/org/springframework/data/redis/core/StreamObjectMapper.java +++ b/src/main/java/org/springframework/data/redis/core/StreamObjectMapper.java @@ -106,12 +106,11 @@ public Object fromHash(Map hash) { @SuppressWarnings({ "unchecked", "rawtypes" }) static MapRecord toMapRecord(HashMapperProvider provider, Record source) { - if (source instanceof ObjectRecord) { - - ObjectRecord entry = ((ObjectRecord) source); + if (source instanceof ObjectRecord entry) { if (entry.getValue() instanceof Map) { - return StreamRecords.newRecord().in(source.getStream()).withId(source.getId()).ofMap((Map) entry.getValue()); + return StreamRecords.newRecord().in(source.getRequiredStream()).withId(source.getId()) + .ofMap((Map) entry.getValue()); } return entry.toMapRecord(provider.getHashMapper(entry.getValue().getClass())); @@ -122,7 +121,7 @@ static MapRecord toMapRecord(HashMapperProviderRedis Documentation: XACK */ default Long acknowledge(String group, Record record) { - return acknowledge(record.getStream(), group, record.getId()); + return acknowledge(record.getRequiredStream(), group, record.getId()); } /** From 33e4ef146930c1a2f898fbf33fa5fd4a2999f073 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Feb 2022 10:54:16 +0100 Subject: [PATCH 07/12] Refine defaulted connection arrangement. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DefaultedRedis…Connection is now deprecated to help with migration towards segregated/commands interface usage. The connection now exposes a commands() object providing access to RedisCommands so that a composite commands object can be accessed independently from the connection. Redis…Commands provider represent entry points to obtain segregated command interfaces. --- .../connection/AbstractRedisConnection.java | 2 +- .../DefaultStringRedisConnection.java | 76 ++++++++++- .../DefaultedRedisClusterConnection.java | 27 +--- .../connection/DefaultedRedisConnection.java | 3 +- .../RedisClusterCommandsProvider.java | 42 ++++++ .../connection/RedisClusterConnection.java | 29 +++-- .../connection/RedisCommandsProvider.java | 121 ++++++++++++++++++ .../redis/connection/RedisConnection.java | 112 +--------------- .../jedis/JedisClusterConnection.java | 68 ++++++---- .../connection/jedis/JedisConnection.java | 60 ++++++--- .../lettuce/LettuceClusterConnection.java | 53 +++++--- .../connection/lettuce/LettuceConnection.java | 49 ++++--- .../connection/RedisConnectionUnitTests.java | 60 +++++++++ 13 files changed, 470 insertions(+), 232 deletions(-) create mode 100644 src/main/java/org/springframework/data/redis/connection/RedisClusterCommandsProvider.java create mode 100644 src/main/java/org/springframework/data/redis/connection/RedisCommandsProvider.java diff --git a/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java index 83a58bcbef..5c9a07a56b 100644 --- a/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java @@ -31,7 +31,7 @@ * @author Mark Paluch * @since 1.4 */ -public abstract class AbstractRedisConnection implements DefaultedRedisConnection { +public abstract class AbstractRedisConnection implements RedisConnection { private @Nullable RedisSentinelConfiguration sentinelConfiguration; private final Map connectionCache = new ConcurrentHashMap<>(); diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 168ac801a7..fa3e9c5086 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -79,6 +79,7 @@ * @author dengliming * @author ihaohong */ +@SuppressWarnings({ "ConstantConditions", "deprecation" }) public class DefaultStringRedisConnection implements StringRedisConnection, DecoratedRedisConnection { private static final byte[][] EMPTY_2D_BYTE_ARRAY = new byte[0][]; @@ -183,6 +184,66 @@ public DefaultStringRedisConnection(RedisConnection connection, RedisSerializer< this.byteGeoResultsToStringGeoResults = Converters.deserializingGeoResultsConverter(serializer); } + @Override + public RedisCommands commands() { + return this; + } + + @Override + public RedisGeoCommands geoCommands() { + return this; + } + + @Override + public RedisHashCommands hashCommands() { + return this; + } + + @Override + public RedisHyperLogLogCommands hyperLogLogCommands() { + return this; + } + + @Override + public RedisKeyCommands keyCommands() { + return this; + } + + @Override + public RedisListCommands listCommands() { + return this; + } + + @Override + public RedisSetCommands setCommands() { + return this; + } + + @Override + public RedisScriptingCommands scriptingCommands() { + return this; + } + + @Override + public RedisServerCommands serverCommands() { + return this; + } + + @Override + public RedisStreamCommands streamCommands() { + return this; + } + + @Override + public RedisStringCommands stringCommands() { + return this; + } + + @Override + public RedisZSetCommands zSetCommands() { + return this; + } + @Override public Long append(byte[] key, byte[] value) { return convertAndReturn(delegate.append(key, value), Converters.identityConverter()); @@ -1000,6 +1061,13 @@ public Set zInterWithScores(Aggregate aggregate, Weights weights, S return convertAndReturn(delegate.zInterWithScores(aggregate, weights, serializeMulti(sets)), tupleToStringTuple); } + @Nullable + @Override + public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + return convertAndReturn(delegate.zInterStore(destKey, aggregate, Weights.of(weights), sets), + Converters.identityConverter()); + } + @Override public Long zInterStore(byte[] destKey, Aggregate aggregate, Weights weights, byte[]... sets) { return convertAndReturn(delegate.zInterStore(destKey, aggregate, weights, sets), Converters.identityConverter()); @@ -1200,6 +1268,13 @@ public Long zUnionStore(byte[] destKey, Aggregate aggregate, Weights weights, by return convertAndReturn(delegate.zUnionStore(destKey, aggregate, weights, sets), Converters.identityConverter()); } + @Nullable + @Override + public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + return convertAndReturn(delegate.zUnionStore(destKey, aggregate, Weights.of(weights), sets), + Converters.identityConverter()); + } + public Long zUnionStore(byte[] destKey, byte[]... sets) { return convertAndReturn(delegate.zUnionStore(destKey, sets), Converters.identityConverter()); } @@ -1292,7 +1367,6 @@ private GeoReference serialize(GeoReference data) { : (GeoReference) data; } - @SuppressWarnings("unchecked") private StreamOffset[] serialize(StreamOffset[] offsets) { return Arrays.stream(offsets).map(it -> StreamOffset.create(serialize(it.getKey()), it.getOffset())) diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java index fb853a0be4..6a06e07aa6 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java @@ -15,21 +15,20 @@ */ package org.springframework.data.redis.connection; -import java.util.Collection; import java.util.List; import java.util.Properties; import java.util.concurrent.TimeUnit; import org.springframework.data.redis.core.types.RedisClientInfo; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; /** * @author Christoph Strobl * @author Mark Paluch * @since 2.0 */ -public interface DefaultedRedisClusterConnection extends RedisClusterConnection, DefaultedRedisConnection { +@Deprecated +public interface DefaultedRedisClusterConnection + extends DefaultedRedisConnection, RedisClusterCommands, RedisClusterServerCommands, RedisClusterCommandsProvider { /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ @Override @@ -150,24 +149,4 @@ default List getClientList(RedisClusterNode node) { return serverCommands().getClientList(node); } - @Nullable - @Override - @SuppressWarnings("unchecked") - default T execute(String command, byte[] key, Collection args) { - - Assert.notNull(command, "Command must not be null!"); - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(args, "Args must not be null!"); - - byte[][] commandArgs = new byte[args.size() + 1][]; - - commandArgs[0] = key; - int targetIndex = 1; - - for (byte[] binaryArgument : args) { - commandArgs[targetIndex++] = binaryArgument; - } - - return (T) execute(command, commandArgs); - } } diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java index 0fd81134ed..4c32134185 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -64,7 +64,8 @@ * @author ihaohong * @since 2.0 */ -public interface DefaultedRedisConnection extends RedisConnection { +@Deprecated +public interface DefaultedRedisConnection extends RedisCommands, RedisCommandsProvider { // KEY COMMANDS diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterCommandsProvider.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterCommandsProvider.java new file mode 100644 index 0000000000..85c36a76d4 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterCommandsProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright 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; + +/** + * Provides access to {@link RedisClusterCommands} and the segregated command interfaces. + * + * @author Mark Paluch + * @since 3.0 + */ +public interface RedisClusterCommandsProvider extends RedisCommandsProvider { + + /** + * Get {@link RedisGeoCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisClusterCommands clusterCommands(); + + /** + * Get {@link RedisServerCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisClusterServerCommands serverCommands(); + +} diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java index 940456b889..a361f7ffa8 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java @@ -21,6 +21,7 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * {@link RedisClusterConnection} allows sending commands to dedicated nodes within the cluster. A @@ -32,7 +33,8 @@ * @author Mark Paluch * @since 1.7 */ -public interface RedisClusterConnection extends RedisConnection, RedisClusterCommands, RedisClusterServerCommands { +public interface RedisClusterConnection + extends RedisConnection, DefaultedRedisClusterConnection, RedisClusterCommandsProvider { /** * @param node must not be {@literal null}. @@ -89,15 +91,22 @@ public interface RedisClusterConnection extends RedisConnection, RedisClusterCom * @since 2.1 */ @Nullable - T execute(String command, byte[] key, Collection args); + default T execute(String command, byte[] key, Collection args) { - /** - * Get {@link RedisClusterServerCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisClusterServerCommands serverCommands() { - return this; + Assert.notNull(command, "Command must not be null!"); + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(args, "Args must not be null!"); + + byte[][] commandArgs = new byte[args.size() + 1][]; + + commandArgs[0] = key; + int targetIndex = 1; + + for (byte[] binaryArgument : args) { + commandArgs[targetIndex++] = binaryArgument; + } + + return (T) execute(command, commandArgs); } + } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisCommandsProvider.java b/src/main/java/org/springframework/data/redis/connection/RedisCommandsProvider.java new file mode 100644 index 0000000000..74e63da957 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/RedisCommandsProvider.java @@ -0,0 +1,121 @@ +/* + * Copyright 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; + +/** + * Provides access to {@link RedisCommands} and the segregated command interfaces. + * + * @author Mark Paluch + * @since 3.0 + */ +public interface RedisCommandsProvider { + + /** + * Get {@link RedisCommands}. + * + * @return never {@literal null}. + * @since 3.0 + */ + RedisCommands commands(); + + /** + * Get {@link RedisGeoCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisGeoCommands geoCommands(); + + /** + * Get {@link RedisHashCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisHashCommands hashCommands(); + + /** + * Get {@link RedisHyperLogLogCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisHyperLogLogCommands hyperLogLogCommands(); + + /** + * Get {@link RedisKeyCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisKeyCommands keyCommands(); + + /** + * Get {@link RedisListCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisListCommands listCommands(); + + /** + * Get {@link RedisSetCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisSetCommands setCommands(); + + /** + * Get {@link RedisScriptingCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisScriptingCommands scriptingCommands(); + + /** + * Get {@link RedisServerCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisServerCommands serverCommands(); + + /** + * Get {@link RedisStreamCommands}. + * + * @return never {@literal null}. + * @since 2.2 + */ + RedisStreamCommands streamCommands(); + + /** + * Get {@link RedisStringCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisStringCommands stringCommands(); + + /** + * Get {@link RedisZSetCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + RedisZSetCommands zSetCommands(); +} diff --git a/src/main/java/org/springframework/data/redis/connection/RedisConnection.java b/src/main/java/org/springframework/data/redis/connection/RedisConnection.java index 0a9e9afa9a..4603b79e09 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisConnection.java @@ -29,117 +29,7 @@ * @author Mark Paluch * @author James Howe */ -public interface RedisConnection extends RedisCommands, AutoCloseable { - - /** - * Get {@link RedisGeoCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisGeoCommands geoCommands() { - return this; - } - - /** - * Get {@link RedisHashCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisHashCommands hashCommands() { - return this; - } - - /** - * Get {@link RedisHyperLogLogCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisHyperLogLogCommands hyperLogLogCommands() { - return this; - } - - /** - * Get {@link RedisKeyCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisKeyCommands keyCommands() { - return this; - } - - /** - * Get {@link RedisListCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisListCommands listCommands() { - return this; - } - - /** - * Get {@link RedisSetCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisSetCommands setCommands() { - return this; - } - - /** - * Get {@link RedisScriptingCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisScriptingCommands scriptingCommands() { - return this; - } - - /** - * Get {@link RedisServerCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisServerCommands serverCommands() { - return this; - } - - /** - * Get {@link RedisStreamCommands}. - * - * @return never {@literal null}. - * @since 2.2 - */ - default RedisStreamCommands streamCommands() { - return this; - } - - /** - * Get {@link RedisStringCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisStringCommands stringCommands() { - return this; - } - - /** - * Get {@link RedisZSetCommands}. - * - * @return never {@literal null}. - * @since 2.0 - */ - default RedisZSetCommands zSetCommands() { - return this; - } +public interface RedisConnection extends RedisCommandsProvider, DefaultedRedisConnection, AutoCloseable { /** * Closes (or quits) the connection. 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 bdbbc5e9d1..d216db5ee7 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 @@ -72,7 +72,7 @@ * @author Pavel Khokhlov * @since 1.7 */ -public class JedisClusterConnection implements DefaultedRedisClusterConnection { +public class JedisClusterConnection implements RedisClusterConnection { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new FallbackExceptionTranslationStrategy( JedisExceptionConverter.INSTANCE); @@ -82,6 +82,16 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { private final Log log = LogFactory.getLog(getClass()); private final JedisCluster cluster; + private final JedisClusterGeoCommands geoCommands = new JedisClusterGeoCommands(this); + private final JedisClusterHashCommands hashCommands = new JedisClusterHashCommands(this); + private final JedisClusterHyperLogLogCommands hllCommands = new JedisClusterHyperLogLogCommands(this); + private final JedisClusterKeyCommands keyCommands = new JedisClusterKeyCommands(this); + private final JedisClusterListCommands listCommands = new JedisClusterListCommands(this); + private final JedisClusterSetCommands setCommands = new JedisClusterSetCommands(this); + private final JedisClusterServerCommands serverCommands = new JedisClusterServerCommands(this); + private final JedisClusterStreamCommands streamCommands = new JedisClusterStreamCommands(this); + private final JedisClusterStringCommands stringCommands = new JedisClusterStringCommands(this); + private final JedisClusterZSetCommands zSetCommands = new JedisClusterZSetCommands(this); private boolean closed; @@ -232,54 +242,64 @@ public List execute(String command, Collection keys, Collection keys(RedisClusterNode node, byte[] pattern) { - return doGetKeyCommands().keys(node, pattern); + return keyCommands.keys(node, pattern); } @Override public Cursor scan(RedisClusterNode node, ScanOptions options) { - return doGetKeyCommands().scan(node, options); + return keyCommands.scan(node, options); } @Override public byte[] randomKey(RedisClusterNode node) { - return doGetKeyCommands().randomKey(node); + return keyCommands.randomKey(node); } @Override @@ -451,12 +467,13 @@ public List clusterGetKeysInSlot(int slot, Integer count) { RedisClusterNode node = clusterGetNodeForSlot(slot); - clusterCommandExecutor + NodeResult> result = clusterCommandExecutor .executeCommandOnSingleNode( (JedisClusterCommandCallback>) client -> JedisConverters.stringListToByteList() .convert(client.clusterGetKeysInSlot(slot, count != null ? count.intValue() : Integer.MAX_VALUE)), node); - return null; + + return result.getValue(); } @Override @@ -481,7 +498,6 @@ public Long clusterCountKeysInSlot(int slot) { return clusterCommandExecutor.executeCommandOnSingleNode( (JedisClusterCommandCallback) client -> client.clusterCountKeysInSlot(slot), node).getValue(); - } @Override 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 92fc89c681..de9a22de0f 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 @@ -70,11 +70,24 @@ public class JedisConnection extends AbstractRedisConnection { private final JedisInvoker statusInvoker = new JedisInvoker((directFunction, pipelineFunction, converter, nullDefault) -> doInvoke(true, directFunction, pipelineFunction, converter, nullDefault)); + private final JedisGeoCommands geoCommands = new JedisGeoCommands(this); + private final JedisHashCommands hashCommands = new JedisHashCommands(this); + private final JedisHyperLogLogCommands hllCommands = new JedisHyperLogLogCommands(this); + private final JedisKeyCommands keyCommands = new JedisKeyCommands(this); + private final JedisListCommands listCommands = new JedisListCommands(this); + private final JedisScriptingCommands scriptingCommands = new JedisScriptingCommands(this); + private final JedisServerCommands serverCommands = new JedisServerCommands(this); + private final JedisSetCommands setCommands = new JedisSetCommands(this); + private final JedisStreamCommands streamCommands = new JedisStreamCommands(this); + private final JedisStringCommands stringCommands = new JedisStringCommands(this); + 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<>(); @@ -189,58 +202,63 @@ protected DataAccessException convertJedisAccessException(Exception ex) { } @Override - public RedisKeyCommands keyCommands() { - return new JedisKeyCommands(this); + public RedisCommands commands() { + return this; } @Override - public RedisStreamCommands streamCommands() { - return new JedisStreamCommands(this); + public RedisGeoCommands geoCommands() { + return geoCommands; } @Override - public RedisStringCommands stringCommands() { - return new JedisStringCommands(this); + public RedisHashCommands hashCommands() { + return hashCommands; + } + + @Override + public RedisHyperLogLogCommands hyperLogLogCommands() { + return hllCommands; + } + + @Override + public RedisKeyCommands keyCommands() { + return keyCommands; } @Override public RedisListCommands listCommands() { - return new JedisListCommands(this); + return listCommands; } @Override public RedisSetCommands setCommands() { - return new JedisSetCommands(this); + return setCommands; } @Override - public RedisZSetCommands zSetCommands() { - return new JedisZSetCommands(this); + public RedisStreamCommands streamCommands() { + return streamCommands; } @Override - public RedisHashCommands hashCommands() { - return new JedisHashCommands(this); + public RedisStringCommands stringCommands() { + return stringCommands; } @Override - public RedisGeoCommands geoCommands() { - return new JedisGeoCommands(this); + public RedisZSetCommands zSetCommands() { + return zSetCommands; } @Override public RedisScriptingCommands scriptingCommands() { - return new JedisScriptingCommands(this); + return scriptingCommands; } @Override public RedisServerCommands serverCommands() { - return new JedisServerCommands(this); - } - - @Override - public RedisHyperLogLogCommands hyperLogLogCommands() { - return new JedisHyperLogLogCommands(this); + return serverCommands; } @Override diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index eb858bd370..0323c92197 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -58,12 +58,22 @@ * @author Mark Paluch * @since 1.7 */ -public class LettuceClusterConnection extends LettuceConnection implements DefaultedRedisClusterConnection { +public class LettuceClusterConnection extends LettuceConnection + implements RedisClusterConnection, DefaultedRedisClusterConnection { static final ExceptionTranslationStrategy exceptionConverter = new PassThroughExceptionTranslationStrategy( LettuceExceptionConverter.INSTANCE); private final Log log = LogFactory.getLog(getClass()); + private final LettuceClusterGeoCommands geoCommands = new LettuceClusterGeoCommands(this); + private final LettuceClusterHashCommands hashCommands = new LettuceClusterHashCommands(this); + private final LettuceClusterHyperLogLogCommands hllCommands = new LettuceClusterHyperLogLogCommands(this); + private final LettuceClusterKeyCommands keyCommands = new LettuceClusterKeyCommands(this); + private final LettuceClusterListCommands listCommands = new LettuceClusterListCommands(this); + private final LettuceClusterStringCommands stringCommands = new LettuceClusterStringCommands(this); + private final LettuceClusterSetCommands setCommands = new LettuceClusterSetCommands(this); + private final LettuceClusterZSetCommands zSetCommands = new LettuceClusterZSetCommands(this); + private final LettuceClusterServerCommands serverCommands = new LettuceClusterServerCommands(this); private ClusterCommandExecutor clusterCommandExecutor; private ClusterTopologyProvider topologyProvider; @@ -198,53 +208,54 @@ private RedisClusterClient getClient() { connectionProvider.getClass().getName())); } + @Override + public org.springframework.data.redis.connection.RedisClusterCommands clusterCommands() { + return this; + } + @Override public RedisGeoCommands geoCommands() { - return new LettuceClusterGeoCommands(this); + return geoCommands; } @Override public RedisHashCommands hashCommands() { - return new LettuceClusterHashCommands(this); + return hashCommands; } @Override public RedisHyperLogLogCommands hyperLogLogCommands() { - return new LettuceClusterHyperLogLogCommands(this); + return hllCommands; } @Override public RedisKeyCommands keyCommands() { - return doGetClusterKeyCommands(); - } - - private LettuceClusterKeyCommands doGetClusterKeyCommands() { - return new LettuceClusterKeyCommands(this); + return keyCommands; } @Override public RedisListCommands listCommands() { - return new LettuceClusterListCommands(this); + return listCommands; } @Override - public RedisStringCommands stringCommands() { - return new LettuceClusterStringCommands(this); + public RedisSetCommands setCommands() { + return setCommands; } @Override - public RedisSetCommands setCommands() { - return new LettuceClusterSetCommands(this); + public RedisClusterServerCommands serverCommands() { + return serverCommands; } @Override - public RedisZSetCommands zSetCommands() { - return new LettuceClusterZSetCommands(this); + public RedisStringCommands stringCommands() { + return stringCommands; } @Override - public RedisClusterServerCommands serverCommands() { - return new LettuceClusterServerCommands(this); + public RedisZSetCommands zSetCommands() { + return zSetCommands; } @Override @@ -438,16 +449,16 @@ public void clusterReplicate(RedisClusterNode master, RedisClusterNode replica) @Override public Set keys(RedisClusterNode node, byte[] pattern) { - return doGetClusterKeyCommands().keys(node, pattern); + return new LettuceClusterKeyCommands(this).keys(node, pattern); } @Override public Cursor scan(RedisClusterNode node, ScanOptions options) { - return doGetClusterKeyCommands().scan(node, options); + return new LettuceClusterKeyCommands(this).scan(node, options); } public byte[] randomKey(RedisClusterNode node) { - return doGetClusterKeyCommands().randomKey(node); + return new LettuceClusterKeyCommands(this).randomKey(node); } @Override 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 b34c959332..a40de2718c 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 @@ -95,6 +95,18 @@ public class LettuceConnection extends AbstractRedisConnection { LettuceExceptionConverter.INSTANCE); private static final TypeHints typeHints = new TypeHints(); + private final LettuceGeoCommands geoCommands = new LettuceGeoCommands(this); + private final LettuceHashCommands hashCommands = new LettuceHashCommands(this); + private final LettuceHyperLogLogCommands hllCommands = new LettuceHyperLogLogCommands(this); + private final LettuceKeyCommands keyCommands = new LettuceKeyCommands(this); + private final LettuceListCommands listCommands = new LettuceListCommands(this); + private final LettuceScriptingCommands scriptingCommands = new LettuceScriptingCommands(this); + private final LettuceSetCommands setCommands = new LettuceSetCommands(this); + private final LettuceServerCommands serverCommands = new LettuceServerCommands(this); + private final LettuceStreamCommands streamCommands = new LettuceStreamCommands(this); + private final LettuceStringCommands stringCommands = new LettuceStringCommands(this); + private final LettuceZSetCommands zSetCommands = new LettuceZSetCommands(this); + private final int defaultDbIndex; private int dbIndex; @@ -231,59 +243,64 @@ protected DataAccessException convertLettuceAccessException(Exception ex) { return EXCEPTION_TRANSLATION.translate(ex); } + @Override + public org.springframework.data.redis.connection.RedisCommands commands() { + return this; + } + @Override public RedisGeoCommands geoCommands() { - return new LettuceGeoCommands(this); + return geoCommands; } @Override public RedisHashCommands hashCommands() { - return new LettuceHashCommands(this); + return hashCommands; } @Override public RedisHyperLogLogCommands hyperLogLogCommands() { - return new LettuceHyperLogLogCommands(this); + return hllCommands; } @Override public RedisKeyCommands keyCommands() { - return new LettuceKeyCommands(this); + return keyCommands; } @Override public RedisListCommands listCommands() { - return new LettuceListCommands(this); + return listCommands; } @Override - public RedisSetCommands setCommands() { - return new LettuceSetCommands(this); + public RedisScriptingCommands scriptingCommands() { + return scriptingCommands; } @Override - public RedisScriptingCommands scriptingCommands() { - return new LettuceScriptingCommands(this); + public RedisSetCommands setCommands() { + return setCommands; } @Override - public RedisStreamCommands streamCommands() { - return new LettuceStreamCommands(this); + public RedisServerCommands serverCommands() { + return serverCommands; } @Override - public RedisStringCommands stringCommands() { - return new LettuceStringCommands(this); + public RedisStreamCommands streamCommands() { + return streamCommands; } @Override - public RedisServerCommands serverCommands() { - return new LettuceServerCommands(this); + public RedisStringCommands stringCommands() { + return stringCommands; } @Override public RedisZSetCommands zSetCommands() { - return new LettuceZSetCommands(this); + return zSetCommands; } @Override diff --git a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java index c4d9167226..dc2c508081 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java @@ -100,6 +100,66 @@ static class AbstractDelegatingRedisConnectionStub extends AbstractRedisConnecti this.delegate = delegate; } + @Override + public RedisCommands commands() { + return null; + } + + @Override + public RedisGeoCommands geoCommands() { + return null; + } + + @Override + public RedisHashCommands hashCommands() { + return null; + } + + @Override + public RedisHyperLogLogCommands hyperLogLogCommands() { + return null; + } + + @Override + public RedisKeyCommands keyCommands() { + return null; + } + + @Override + public RedisListCommands listCommands() { + return null; + } + + @Override + public RedisSetCommands setCommands() { + return null; + } + + @Override + public RedisScriptingCommands scriptingCommands() { + return null; + } + + @Override + public RedisServerCommands serverCommands() { + return null; + } + + @Override + public RedisStreamCommands streamCommands() { + return null; + } + + @Override + public RedisStringCommands stringCommands() { + return null; + } + + @Override + public RedisZSetCommands zSetCommands() { + return null; + } + @Override protected boolean isActive(RedisNode node) { return ObjectUtils.nullSafeEquals(activeNode, node); From 35b01406ba1719935e68183c4f815113589485b3 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Feb 2022 14:47:55 +0100 Subject: [PATCH 08/12] =?UTF-8?q?Replace=20Bound=E2=80=A6Operations=20impl?= =?UTF-8?q?ementation=20with=20a=20proxy=20factory.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/BoundOperationsProxyFactory.java | 251 ++++++++++++ .../data/redis/core/BoundSetOperations.java | 66 +++- .../redis/core/DefaultBoundGeoOperations.java | 144 ------- .../core/DefaultBoundHashOperations.java | 159 -------- .../redis/core/DefaultBoundKeyOperations.java | 70 ---- .../core/DefaultBoundListOperations.java | 181 --------- .../redis/core/DefaultBoundSetOperations.java | 177 --------- .../core/DefaultBoundStreamOperations.java | 139 ------- .../core/DefaultBoundValueOperations.java | 165 -------- .../core/DefaultBoundZSetOperations.java | 370 ------------------ .../data/redis/core/RedisTemplate.java | 19 +- .../BoundOperationsProxyFactoryUnitTests.java | 83 ++++ .../DefaultBoundValueOperationsUnitTests.java | 119 ------ .../DefaultBoundZSetOperationsUnitTests.java | 49 --- 14 files changed, 407 insertions(+), 1585 deletions(-) create mode 100644 src/main/java/org/springframework/data/redis/core/BoundOperationsProxyFactory.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundListOperations.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundSetOperations.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java delete mode 100644 src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java create mode 100644 src/test/java/org/springframework/data/redis/core/BoundOperationsProxyFactoryUnitTests.java delete mode 100644 src/test/java/org/springframework/data/redis/core/DefaultBoundValueOperationsUnitTests.java delete mode 100644 src/test/java/org/springframework/data/redis/core/DefaultBoundZSetOperationsUnitTests.java diff --git a/src/main/java/org/springframework/data/redis/core/BoundOperationsProxyFactory.java b/src/main/java/org/springframework/data/redis/core/BoundOperationsProxyFactory.java new file mode 100644 index 0000000000..95352acb93 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/core/BoundOperationsProxyFactory.java @@ -0,0 +1,251 @@ +/* + * Copyright 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.core; + +import java.lang.reflect.Method; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor; +import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.stream.ReadOffset; +import org.springframework.data.redis.connection.stream.StreamOffset; +import org.springframework.lang.Nullable; +import org.springframework.util.ReflectionUtils; + +/** + * Utility to create implementation objects for {@code Bound…Operations} so that bound key interfaces can be implemented + * automatically by translating interface calls to actual {@code …Operations} interfaces. + * + * @author Mark Paluch + * @since 3.0 + */ +class BoundOperationsProxyFactory { + + private final Map targetMethodCache = new ConcurrentHashMap<>(); + + /** + * Create a proxy object that implements {@link Class boundOperationsInterface} using the given {@code key} and + * {@link DataType}. Calls to {@code Bound…Operations} methods are bridged by forwarding these either to the + * {@code operationsTarget} or a default implementation. + * + * @param boundOperationsInterface the {@code Bound…Operations} interface. + * @param key the bound key. + * @param type the {@link DataType} for which to create a proxy object. + * @param operations the {@link RedisOperations} instance. + * @param operationsTargetFunction function to extract the actual delegate for method calls. + * @param + * @return the proxy object. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public T createProxy(Class boundOperationsInterface, Object key, DataType type, + RedisOperations operations, Function, Object> operationsTargetFunction) { + + DefaultBoundKeyOperations delegate = new DefaultBoundKeyOperations(type, key, (RedisOperations) operations); + Object operationsTarget = operationsTargetFunction.apply(operations); + + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.addInterface(boundOperationsInterface); + proxyFactory.addAdvice(new DefaultMethodInvokingMethodInterceptor()); + proxyFactory.addAdvice( + new BoundOperationsMethodInterceptor(key, operations, boundOperationsInterface, operationsTarget, delegate)); + + return (T) proxyFactory.getProxy(); + } + + Method lookupRequiredMethod(Method method, Class targetClass, boolean considerKeyArgument) { + + Method target = lookupMethod(method, targetClass, considerKeyArgument); + + if (target == null) { + throw new IllegalArgumentException("Cannot lookup target method for %s in class %s. This appears to be a bug." + .formatted(method, targetClass.getName())); + } + + return target; + } + + @Nullable + Method lookupMethod(Method method, Class targetClass, boolean considerKeyArgument) { + + return targetMethodCache.computeIfAbsent(method, it -> { + + Class[] paramTypes; + + if (isStreamRead(method)) { + paramTypes = new Class[it.getParameterCount()]; + System.arraycopy(it.getParameterTypes(), 0, paramTypes, 0, paramTypes.length - 1); + paramTypes[paramTypes.length - 1] = StreamOffset[].class; + } else if (considerKeyArgument) { + + paramTypes = new Class[it.getParameterCount() + 1]; + paramTypes[0] = Object.class; + System.arraycopy(it.getParameterTypes(), 0, paramTypes, 1, paramTypes.length - 1); + } else { + paramTypes = it.getParameterTypes(); + } + + return ReflectionUtils.findMethod(targetClass, method.getName(), paramTypes); + }); + } + + private boolean isStreamRead(Method method) { + return method.getName().equals("read") + && method.getParameterTypes()[method.getParameterCount() - 1].equals(ReadOffset.class); + } + + /** + * {@link MethodInterceptor} to delegate proxy calls to either {@link RedisOperations}, {@code key}, + * {@link DefaultBoundKeyOperations} or the {@code operationsTarget} such as {@link ValueOperations}. + */ + class BoundOperationsMethodInterceptor implements MethodInterceptor { + + private final Class boundOperationsInterface; + private final Object operationsTarget; + private final DefaultBoundKeyOperations delegate; + + public BoundOperationsMethodInterceptor(Object key, RedisOperations operations, + Class boundOperationsInterface, Object operationsTarget, DefaultBoundKeyOperations delegate) { + + this.boundOperationsInterface = boundOperationsInterface; + this.operationsTarget = operationsTarget; + this.delegate = delegate; + } + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + + Method method = invocation.getMethod(); + + switch (method.getName()) { + case "getKey": + return delegate.getKey(); + + case "rename": + delegate.rename(invocation.getArguments()[0]); + return null; + + case "getOperations": + return delegate.getOps(); + } + + if (method.getDeclaringClass() == boundOperationsInterface) { + return doInvoke(invocation, method, operationsTarget, true); + } + + return doInvoke(invocation, method, delegate, false); + } + + @Nullable + private Object doInvoke(MethodInvocation invocation, Method method, Object target, boolean considerKeyArgument) { + + Method backingMethod = lookupRequiredMethod(method, target.getClass(), considerKeyArgument); + + Object[] args; + Object[] invocationArguments = invocation.getArguments(); + + if (isStreamRead(method)) { + // stream.read requires translation to StreamOffset using the bound key. + args = new Object[backingMethod.getParameterCount()]; + System.arraycopy(invocationArguments, 0, args, 0, args.length - 1); + args[args.length - 1] = new StreamOffset[] { + StreamOffset.create(delegate.getKey(), (ReadOffset) invocationArguments[invocationArguments.length - 1]) }; + } else if (backingMethod.getParameterCount() > 0 && backingMethod.getParameterTypes()[0].equals(Object.class)) { + + args = new Object[backingMethod.getParameterCount()]; + args[0] = delegate.getKey(); + System.arraycopy(invocationArguments, 0, args, 1, args.length - 1); + } else { + args = invocationArguments; + } + + try { + return backingMethod.invoke(target, args); + } catch (ReflectiveOperationException e) { + ReflectionUtils.handleReflectionException(e); + throw new UnsupportedOperationException("Should not happen", e); + } + } + } + + /** + * Default {@link BoundKeyOperations} implementation. Meant for internal usage. + * + * @author Costin Leau + * @author Christoph Strobl + */ + static class DefaultBoundKeyOperations implements BoundKeyOperations { + + private final DataType type; + private Object key; + private final RedisOperations ops; + + DefaultBoundKeyOperations(DataType type, Object key, RedisOperations operations) { + this.type = type; + + this.key = key; + this.ops = operations; + } + + @Override + public Object getKey() { + return key; + } + + @Override + public Boolean expire(long timeout, TimeUnit unit) { + return ops.expire(key, timeout, unit); + } + + @Override + public Boolean expireAt(Date date) { + return ops.expireAt(key, date); + } + + @Override + public Long getExpire() { + return ops.getExpire(key); + } + + @Override + public Boolean persist() { + return ops.persist(key); + } + + @Override + public void rename(Object newKey) { + if (ops.hasKey(key)) { + ops.rename(key, newKey); + } + key = newKey; + } + + public DataType getType() { + return type; + } + + public RedisOperations getOps() { + return ops; + } + } +} diff --git a/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java b/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java index 9bbcad0383..45125bbc8a 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java @@ -182,19 +182,71 @@ public interface BoundSetOperations extends BoundKeyOperations { * @param key must not be {@literal null}. * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFF + * @deprecated since 3.0, use {@link #difference(Object)} instead to follow a consistent method naming scheme. */ @Nullable - Set diff(K key); + default Set diff(K key) { + return difference(key); + } + + /** + * Diff all sets for given the bound key and {@code key}. + * + * @param key must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 3.0 + * @see Redis Documentation: SDIFF + */ + @Nullable + Set difference(K key); + + /** + * Diff all sets for given the bound key and {@code keys}. + * + * @param keys must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @see Redis Documentation: SDIFF + * @deprecated since 3.0, use {@link #difference(Collection)} instead to follow a consistent method naming scheme. + */ + @Nullable + default Set diff(Collection keys) { + return difference(keys); + } /** * Diff all sets for given the bound key and {@code keys}. * * @param keys must not be {@literal null}. * @return {@literal null} when used in pipeline / transaction. + * @since 3.0 * @see Redis Documentation: SDIFF */ @Nullable - Set diff(Collection keys); + Set difference(Collection keys); + + /** + * Diff all sets for given the bound key and {@code keys} and store result in {@code destKey}. + * + * @param keys must not be {@literal null}. + * @param destKey must not be {@literal null}. + * @see Redis Documentation: SDIFFSTORE + * @deprecated since 3.0, use {@link #differenceAndStore(Object, Object)} instead to follow a consistent method naming + * scheme.. + */ + @Deprecated + default void diffAndStore(K keys, K destKey) { + differenceAndStore(keys, destKey); + } + + /** + * Diff all sets for given the bound key and {@code keys} and store result in {@code destKey}. + * + * @param keys must not be {@literal null}. + * @param destKey must not be {@literal null}. + * @since 3.0 + * @see Redis Documentation: SDIFFSTORE + */ + void differenceAndStore(K keys, K destKey); /** * Diff all sets for given the bound key and {@code keys} and store result in {@code destKey}. @@ -202,17 +254,23 @@ public interface BoundSetOperations extends BoundKeyOperations { * @param keys must not be {@literal null}. * @param destKey must not be {@literal null}. * @see Redis Documentation: SDIFFSTORE + * @deprecated since 3.0, use {@link #differenceAndStore(Collection, Object)} instead to follow a consistent method + * naming scheme. */ - void diffAndStore(K keys, K destKey); + @Deprecated + default void diffAndStore(Collection keys, K destKey) { + differenceAndStore(keys, destKey); + } /** * Diff all sets for given the bound key and {@code keys} and store result in {@code destKey}. * * @param keys must not be {@literal null}. * @param destKey must not be {@literal null}. + * @since 3.0 * @see Redis Documentation: SDIFFSTORE */ - void diffAndStore(Collection keys, K destKey); + void differenceAndStore(Collection keys, K destKey); /** * Get all elements of set at the bound key. diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java deleted file mode 100644 index d78ecd8451..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundGeoOperations.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2016-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.core; - -import java.util.List; -import java.util.Map; - -import org.springframework.data.geo.Circle; -import org.springframework.data.geo.Distance; -import org.springframework.data.geo.GeoResults; -import org.springframework.data.geo.Metric; -import org.springframework.data.geo.Point; -import org.springframework.data.redis.connection.DataType; -import org.springframework.data.redis.connection.RedisGeoCommands; -import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; -import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; -import org.springframework.data.redis.domain.geo.GeoReference; -import org.springframework.data.redis.domain.geo.GeoShape; - -/** - * Default implementation of {@link BoundGeoOperations}. - * - * @author Ninad Divadkar - * @author Christoph Strobl - * @author Mark Paluch - * @since 1.8 - */ -class DefaultBoundGeoOperations extends DefaultBoundKeyOperations implements BoundGeoOperations { - - private final GeoOperations ops; - - /** - * Constructs a new {@code DefaultBoundGeoOperations}. - * - * @param key must not be {@literal null}. - * @param operations must not be {@literal null}. - */ - DefaultBoundGeoOperations(K key, RedisOperations operations) { - - super(key, operations); - this.ops = operations.opsForGeo(); - } - - @Override - public Long add(Point point, M member) { - return ops.add(getKey(), point, member); - } - - @Override - public Long add(GeoLocation location) { - return ops.add(getKey(), location); - } - - @Override - public Long add(Map memberCoordinateMap) { - return ops.add(getKey(), memberCoordinateMap); - } - - @Override - public Long add(Iterable> locations) { - return ops.add(getKey(), locations); - } - - @Override - public Distance distance(M member1, M member2) { - return ops.distance(getKey(), member1, member2); - } - - @Override - public Distance distance(M member1, M member2, Metric unit) { - return ops.distance(getKey(), member1, member2, unit); - } - - @Override - public List hash(M... members) { - return ops.hash(getKey(), members); - } - - @Override - public List position(M... members) { - return ops.position(getKey(), members); - } - - @Override - public GeoResults> radius(Circle within) { - return ops.radius(getKey(), within); - } - - @Override - public GeoResults> radius(Circle within, GeoRadiusCommandArgs param) { - return ops.radius(getKey(), within, param); - } - - @Override - public GeoResults> radius(M member, double radius) { - return ops.radius(getKey(), member, radius); - } - - @Override - public GeoResults> radius(M member, Distance distance) { - return ops.radius(getKey(), member, distance); - } - - @Override - public GeoResults> radius(M member, Distance distance, GeoRadiusCommandArgs param) { - return ops.radius(getKey(), member, distance, param); - } - - @Override - public Long remove(M... members) { - return ops.remove(getKey(), members); - } - - @Override - public GeoResults> search(GeoReference reference, - GeoShape geoPredicate, RedisGeoCommands.GeoSearchCommandArgs args) { - return ops.search(getKey(), reference, geoPredicate, args); - } - - @Override - public Long searchAndStore(K destKey, GeoReference reference, - GeoShape geoPredicate, RedisGeoCommands.GeoSearchStoreCommandArgs args) { - return ops.searchAndStore(getKey(), destKey, reference, geoPredicate, args); - } - - @Override - public DataType getType() { - return DataType.ZSET; - } - -} diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java deleted file mode 100644 index 3c0a7d4b94..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2011-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.core; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.springframework.data.redis.connection.DataType; -import org.springframework.lang.Nullable; - -/** - * Default implementation for {@link HashOperations}. - * - * @author Costin Leau - * @author Christoph Strobl - * @author Ninad Divadkar - */ -class DefaultBoundHashOperations extends DefaultBoundKeyOperations - implements BoundHashOperations { - - private final HashOperations ops; - - /** - * Constructs a new DefaultBoundHashOperations instance. - * - * @param key - * @param operations - */ - DefaultBoundHashOperations(H key, RedisOperations operations) { - super(key, operations); - this.ops = operations.opsForHash(); - } - - @Override - public Long delete(Object... keys) { - return ops.delete(getKey(), keys); - } - - @Override - public HV get(Object key) { - return ops.get(getKey(), key); - } - - @Override - public List multiGet(Collection hashKeys) { - return ops.multiGet(getKey(), hashKeys); - } - - @Override - public RedisOperations getOperations() { - return ops.getOperations(); - } - - @Override - public Boolean hasKey(Object key) { - return ops.hasKey(getKey(), key); - } - - @Override - public Long increment(HK key, long delta) { - return ops.increment(getKey(), key, delta); - } - - @Override - public Double increment(HK key, double delta) { - return ops.increment(getKey(), key, delta); - } - - @Nullable - @Override - public HK randomKey() { - return ops.randomKey(getKey()); - } - - @Nullable - @Override - public Entry randomEntry() { - return ops.randomEntry(getKey()); - } - - @Nullable - @Override - public List randomKeys(long count) { - return ops.randomKeys(getKey(), count); - } - - @Nullable - @Override - public Map randomEntries(long count) { - return ops.randomEntries(getKey(), count); - } - - @Override - public Set keys() { - return ops.keys(getKey()); - } - - @Nullable - @Override - public Long lengthOfValue(HK hashKey) { - return ops.lengthOfValue(getKey(), hashKey); - } - - @Override - public Long size() { - return ops.size(getKey()); - } - - @Override - public void putAll(Map m) { - ops.putAll(getKey(), m); - } - - @Override - public void put(HK key, HV value) { - ops.put(getKey(), key, value); - } - - @Override - public Boolean putIfAbsent(HK key, HV value) { - return ops.putIfAbsent(getKey(), key, value); - } - - @Override - public List values() { - return ops.values(getKey()); - } - - @Override - public Map entries() { - return ops.entries(getKey()); - } - - @Override - public DataType getType() { - return DataType.HASH; - } - - @Override - public Cursor> scan(ScanOptions options) { - return ops.scan(getKey(), options); - } -} diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java deleted file mode 100644 index 834cc5a84b..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2011-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.core; - -import java.util.Date; -import java.util.concurrent.TimeUnit; - -/** - * Default {@link BoundKeyOperations} implementation. Meant for internal usage. - * - * @author Costin Leau - * @author Christoph Strobl - */ -abstract class DefaultBoundKeyOperations implements BoundKeyOperations { - - private K key; - private final RedisOperations ops; - - DefaultBoundKeyOperations(K key, RedisOperations operations) { - - this.key = key; - this.ops = operations; - } - - @Override - public K getKey() { - return key; - } - - @Override - public Boolean expire(long timeout, TimeUnit unit) { - return ops.expire(key, timeout, unit); - } - - @Override - public Boolean expireAt(Date date) { - return ops.expireAt(key, date); - } - - @Override - public Long getExpire() { - return ops.getExpire(key); - } - - @Override - public Boolean persist() { - return ops.persist(key); - } - - @Override - public void rename(K newKey) { - if (ops.hasKey(key)) { - ops.rename(key, newKey); - } - key = newKey; - } -} diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundListOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundListOperations.java deleted file mode 100644 index 9d3fe76a93..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundListOperations.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2011-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.core; - -import java.time.Duration; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.springframework.data.redis.connection.DataType; -import org.springframework.data.redis.connection.RedisListCommands.Direction; - -/** - * Default implementation for {@link BoundListOperations}. - * - * @author Costin Leau - * @author Mark Paluch - */ -class DefaultBoundListOperations extends DefaultBoundKeyOperations implements BoundListOperations { - - private final ListOperations ops; - - /** - * Constructs a new DefaultBoundListOperations instance. - * - * @param key - * @param operations - */ - DefaultBoundListOperations(K key, RedisOperations operations) { - - super(key, operations); - this.ops = operations.opsForList(); - } - - @Override - public RedisOperations getOperations() { - return ops.getOperations(); - } - - @Override - public V index(long index) { - return ops.index(getKey(), index); - } - - @Override - public Long indexOf(V value) { - return ops.indexOf(getKey(), value); - } - - @Override - public Long lastIndexOf(V value) { - return ops.lastIndexOf(getKey(), value); - } - - @Override - public V leftPop() { - return ops.leftPop(getKey()); - } - - @Override - public List leftPop(long count) { - return ops.leftPop(getKey(), count); - } - - @Override - public V leftPop(long timeout, TimeUnit unit) { - return ops.leftPop(getKey(), timeout, unit); - } - - @Override - public Long leftPush(V value) { - return ops.leftPush(getKey(), value); - } - - @Override - public Long leftPushAll(V... values) { - return ops.leftPushAll(getKey(), values); - } - - @Override - public Long leftPushIfPresent(V value) { - return ops.leftPushIfPresent(getKey(), value); - } - - @Override - public Long leftPush(V pivot, V value) { - return ops.leftPush(getKey(), pivot, value); - } - - @Override - public Long size() { - return ops.size(getKey()); - } - - @Override - public List range(long start, long end) { - return ops.range(getKey(), start, end); - } - - @Override - public Long remove(long i, Object value) { - return ops.remove(getKey(), i, value); - } - - @Override - public V rightPop() { - return ops.rightPop(getKey()); - } - - @Override - public List rightPop(long count) { - return ops.rightPop(getKey(), count); - } - - @Override - public V rightPop(long timeout, TimeUnit unit) { - return ops.rightPop(getKey(), timeout, unit); - } - - @Override - public Long rightPushIfPresent(V value) { - return ops.rightPushIfPresent(getKey(), value); - } - - @Override - public Long rightPush(V value) { - return ops.rightPush(getKey(), value); - } - - @Override - public Long rightPushAll(V... values) { - return ops.rightPushAll(getKey(), values); - } - - @Override - public Long rightPush(V pivot, V value) { - return ops.rightPush(getKey(), pivot, value); - } - - @Override - public V move(Direction from, K destinationKey, Direction to) { - return ops.move(getKey(), from, destinationKey, to); - } - - @Override - public V move(Direction from, K destinationKey, Direction to, Duration timeout) { - return ops.move(getKey(), from, destinationKey, to, timeout); - } - - @Override - public V move(Direction from, K destinationKey, Direction to, long timeout, TimeUnit unit) { - return ops.move(getKey(), from, destinationKey, to, timeout, unit); - } - - @Override - public void trim(long start, long end) { - ops.trim(getKey(), start, end); - } - - @Override - public void set(long index, V value) { - ops.set(getKey(), index, value); - } - - @Override - public DataType getType() { - return DataType.LIST; - } -} diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundSetOperations.java deleted file mode 100644 index 4b262e649e..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundSetOperations.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2011-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.core; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.springframework.data.redis.connection.DataType; - -/** - * Default implementation for {@link BoundSetOperations}. - * - * @author Costin Leau - * @author Christoph Strobl - */ -class DefaultBoundSetOperations extends DefaultBoundKeyOperations implements BoundSetOperations { - - private final SetOperations ops; - - /** - * Constructs a new DefaultBoundSetOperations instance. - * - * @param key - * @param operations - */ - DefaultBoundSetOperations(K key, RedisOperations operations) { - - super(key, operations); - this.ops = operations.opsForSet(); - } - - @Override - public Long add(V... values) { - return ops.add(getKey(), values); - } - - @Override - public Set diff(K key) { - return ops.difference(getKey(), key); - } - - @Override - public Set diff(Collection keys) { - return ops.difference(getKey(), keys); - } - - @Override - public void diffAndStore(K key, K destKey) { - ops.differenceAndStore(getKey(), key, destKey); - } - - @Override - public void diffAndStore(Collection keys, K destKey) { - ops.differenceAndStore(getKey(), keys, destKey); - } - - @Override - public RedisOperations getOperations() { - return ops.getOperations(); - } - - @Override - public Set intersect(K key) { - return ops.intersect(getKey(), key); - } - - @Override - public Set intersect(Collection keys) { - return ops.intersect(getKey(), keys); - } - - @Override - public void intersectAndStore(K key, K destKey) { - ops.intersectAndStore(getKey(), key, destKey); - } - - @Override - public void intersectAndStore(Collection keys, K destKey) { - ops.intersectAndStore(getKey(), keys, destKey); - } - - @Override - public Boolean isMember(Object o) { - return ops.isMember(getKey(), o); - } - - @Override - public Map isMember(Object... objects) { - return ops.isMember(getKey(), objects); - } - - @Override - public Set members() { - return ops.members(getKey()); - } - - @Override - public Boolean move(K destKey, V value) { - return ops.move(getKey(), value, destKey); - } - - @Override - public V randomMember() { - return ops.randomMember(getKey()); - } - - @Override - public Set distinctRandomMembers(long count) { - return ops.distinctRandomMembers(getKey(), count); - } - - @Override - public List randomMembers(long count) { - return ops.randomMembers(getKey(), count); - } - - @Override - public Long remove(Object... values) { - return ops.remove(getKey(), values); - } - - @Override - public V pop() { - return ops.pop(getKey()); - } - - @Override - public Long size() { - return ops.size(getKey()); - } - - @Override - public Set union(K key) { - return ops.union(getKey(), key); - } - - @Override - public Set union(Collection keys) { - return ops.union(getKey(), keys); - } - - @Override - public void unionAndStore(K key, K destKey) { - ops.unionAndStore(getKey(), key, destKey); - } - - @Override - public void unionAndStore(Collection keys, K destKey) { - ops.unionAndStore(getKey(), keys, destKey); - } - - @Override - public DataType getType() { - return DataType.SET; - } - - @Override - public Cursor scan(ScanOptions options) { - return ops.scan(getKey(), options); - } -} diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java deleted file mode 100644 index 579c527b30..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundStreamOperations.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2018-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.core; - -import java.util.List; -import java.util.Map; - -import org.springframework.data.domain.Range; -import org.springframework.data.redis.connection.DataType; -import org.springframework.data.redis.connection.Limit; -import org.springframework.data.redis.connection.stream.Consumer; -import org.springframework.data.redis.connection.stream.MapRecord; -import org.springframework.data.redis.connection.stream.ReadOffset; -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.lang.Nullable; - -/** - * Default implementation for {@link BoundStreamOperations}. - * - * @author Mark Paluch - * @author Christoph Strobl - * @since 2.2 - */ -class DefaultBoundStreamOperations extends DefaultBoundKeyOperations - implements BoundStreamOperations { - - private final StreamOperations ops; - - /** - * Constructs a new DefaultBoundSetOperations instance. - * - * @param key - * @param operations - */ - DefaultBoundStreamOperations(K key, RedisOperations operations) { - - super(key, operations); - this.ops = operations.opsForStream(); - } - - @Nullable - @Override - public Long acknowledge(String group, String... recordIds) { - return ops.acknowledge(getKey(), group, recordIds); - } - - @Nullable - @Override - public RecordId add(Map body) { - return ops.add(getKey(), body); - } - - @Nullable - @Override - public Long delete(String... recordIds) { - return ops.delete(getKey(), recordIds); - } - - @Nullable - @Override - public String createGroup(ReadOffset readOffset, String group) { - return ops.createGroup(getKey(), readOffset, group); - } - - @Nullable - @Override - public Boolean deleteConsumer(Consumer consumer) { - return ops.deleteConsumer(getKey(), consumer); - } - - @Nullable - @Override - public Boolean destroyGroup(String group) { - return ops.destroyGroup(getKey(), group); - } - - @Nullable - @Override - public Long size() { - return ops.size(getKey()); - } - - @Nullable - @Override - public List> range(Range range, Limit limit) { - return ops.range(getKey(), range, limit); - } - - @Nullable - @Override - public List> read(StreamReadOptions readOptions, ReadOffset readOffset) { - return ops.read(readOptions, StreamOffset.create(getKey(), readOffset)); - } - - @Nullable - @Override - public List> read(Consumer consumer, StreamReadOptions readOptions, ReadOffset readOffset) { - return ops.read(consumer, readOptions, StreamOffset.create(getKey(), readOffset)); - } - - @Nullable - @Override - public List> reverseRange(Range range, Limit limit) { - return ops.reverseRange(getKey(), range, limit); - } - - @Nullable - @Override - public Long trim(long count) { - return trim(count, false); - } - - @Nullable - @Override - public Long trim(long count, boolean approximateTrimming) { - return ops.trim(getKey(), count, approximateTrimming); - } - - @Nullable - @Override - public DataType getType() { - return DataType.STREAM; - } -} diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java deleted file mode 100644 index f3861848bb..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundValueOperations.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2011-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.core; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; - -import org.springframework.data.redis.connection.DataType; -import org.springframework.lang.Nullable; - -/** - * @author Costin Leau - * @author Jiahe Cai - * @author Mark Paluch - */ -class DefaultBoundValueOperations extends DefaultBoundKeyOperations implements BoundValueOperations { - - private final ValueOperations ops; - - /** - * Constructs a new {@link DefaultBoundValueOperations} instance. - * - * @param key - * @param operations - */ - DefaultBoundValueOperations(K key, RedisOperations operations) { - - super(key, operations); - this.ops = operations.opsForValue(); - } - - @Override - public V get() { - return ops.get(getKey()); - } - - @Nullable - @Override - public V getAndDelete() { - return ops.getAndDelete(getKey()); - } - - @Nullable - @Override - public V getAndExpire(long timeout, TimeUnit unit) { - return ops.getAndExpire(getKey(), timeout, unit); - } - - @Nullable - @Override - public V getAndExpire(Duration timeout) { - return ops.getAndExpire(getKey(), timeout); - } - - @Nullable - @Override - public V getAndPersist() { - return ops.getAndPersist(getKey()); - } - - @Override - public V getAndSet(V value) { - return ops.getAndSet(getKey(), value); - } - - @Override - public Long increment() { - return ops.increment(getKey()); - } - - @Override - public Long increment(long delta) { - return ops.increment(getKey(), delta); - } - - @Override - public Double increment(double delta) { - return ops.increment(getKey(), delta); - } - - @Override - public Long decrement() { - return ops.decrement(getKey()); - } - - @Override - public Long decrement(long delta) { - return ops.decrement(getKey(), delta); - } - - @Override - public Integer append(String value) { - return ops.append(getKey(), value); - } - - @Override - public String get(long start, long end) { - return ops.get(getKey(), start, end); - } - - @Override - public void set(V value, long timeout, TimeUnit unit) { - ops.set(getKey(), value, timeout, unit); - } - - @Override - public void set(V value) { - ops.set(getKey(), value); - } - - @Override - public Boolean setIfAbsent(V value) { - return ops.setIfAbsent(getKey(), value); - } - - @Override - public Boolean setIfAbsent(V value, long timeout, TimeUnit unit) { - return ops.setIfAbsent(getKey(), value, timeout, unit); - } - - @Nullable - @Override - public Boolean setIfPresent(V value) { - return ops.setIfPresent(getKey(), value); - } - - @Nullable - @Override - public Boolean setIfPresent(V value, long timeout, TimeUnit unit) { - return ops.setIfPresent(getKey(), value, timeout, unit); - } - - @Override - public void set(V value, long offset) { - ops.set(getKey(), value, offset); - } - - @Override - public Long size() { - return ops.size(getKey()); - } - - @Override - public RedisOperations getOperations() { - return ops.getOperations(); - } - - @Override - public DataType getType() { - return DataType.STRING; - } -} diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java deleted file mode 100644 index b440ba08f3..0000000000 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 2011-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.core; - -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.springframework.data.redis.connection.DataType; -import org.springframework.data.redis.connection.Limit; -import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; -import org.springframework.data.redis.connection.RedisZSetCommands.Range; -import org.springframework.data.redis.connection.zset.Weights; -import org.springframework.data.redis.core.ZSetOperations.TypedTuple; -import org.springframework.lang.Nullable; - -/** - * Default implementation for {@link BoundZSetOperations}. - * - * @author Costin Leau - * @author Christoph Strobl - * @author Mark Paluch - * @author Wongoo (望哥) - * @author Andrey Shlykov - */ -class DefaultBoundZSetOperations extends DefaultBoundKeyOperations implements BoundZSetOperations { - - private final ZSetOperations ops; - - /** - * Constructs a new DefaultBoundZSetOperations instance. - * - * @param key - * @param operations - */ - DefaultBoundZSetOperations(K key, RedisOperations operations) { - - super(key, operations); - this.ops = operations.opsForZSet(); - } - - @Override - public Boolean add(V value, double score) { - return ops.add(getKey(), value, score); - } - - @Override - public Boolean addIfAbsent(V value, double score) { - return ops.addIfAbsent(getKey(), value, score); - } - - @Override - public Long add(Set> tuples) { - return ops.add(getKey(), tuples); - } - - @Override - public Long addIfAbsent(Set> tuples) { - return ops.addIfAbsent(getKey(), tuples); - } - - @Override - public Double incrementScore(V value, double delta) { - return ops.incrementScore(getKey(), value, delta); - } - - @Override - public V randomMember() { - return ops.randomMember(getKey()); - } - - @Nullable - @Override - public Set distinctRandomMembers(long count) { - return ops.distinctRandomMembers(getKey(), count); - } - - @Nullable - @Override - public List randomMembers(long count) { - return ops.randomMembers(getKey(), count); - } - - @Override - public TypedTuple randomMemberWithScore() { - return ops.randomMemberWithScore(getKey()); - } - - @Nullable - @Override - public Set> distinctRandomMembersWithScore(long count) { - return ops.distinctRandomMembersWithScore(getKey(), count); - } - - @Nullable - @Override - public List> randomMembersWithScore(long count) { - return ops.randomMembersWithScore(getKey(), count); - } - - @Override - public RedisOperations getOperations() { - return ops.getOperations(); - } - - @Override - public Set range(long start, long end) { - return ops.range(getKey(), start, end); - } - - @Override - public Set rangeByScore(double min, double max) { - return ops.rangeByScore(getKey(), min, max); - } - - @Override - public Set> rangeByScoreWithScores(double min, double max) { - return ops.rangeByScoreWithScores(getKey(), min, max); - } - - @Override - public Set> rangeWithScores(long start, long end) { - return ops.rangeWithScores(getKey(), start, end); - } - - @Override - public Set reverseRangeByScore(double min, double max) { - return ops.reverseRangeByScore(getKey(), min, max); - } - - @Override - public Set> reverseRangeByScoreWithScores(double min, double max) { - return ops.reverseRangeByScoreWithScores(getKey(), min, max); - } - - @Override - public Set> reverseRangeWithScores(long start, long end) { - return ops.reverseRangeWithScores(getKey(), start, end); - } - - @Override - public Set rangeByLex(Range range, Limit limit) { - return ops.rangeByLex(getKey(), range, limit); - } - - @Override - public Set reverseRangeByLex(Range range, Limit limit) { - return ops.reverseRangeByLex(getKey(), range, limit); - } - - @Override - public Long rank(Object o) { - return ops.rank(getKey(), o); - } - - @Override - public Long reverseRank(Object o) { - return ops.reverseRank(getKey(), o); - } - - @Override - public Double score(Object o) { - return ops.score(getKey(), o); - } - - @Override - public List score(Object... o) { - return ops.score(getKey(), o); - } - - @Override - public Long remove(Object... values) { - return ops.remove(getKey(), values); - } - - @Override - public Long removeRange(long start, long end) { - return ops.removeRange(getKey(), start, end); - } - - @Override - public Long removeRangeByLex(Range range) { - return ops.removeRangeByLex(getKey(), range); - } - - @Override - public Long removeRangeByScore(double min, double max) { - return ops.removeRangeByScore(getKey(), min, max); - } - - @Override - public Set reverseRange(long start, long end) { - return ops.reverseRange(getKey(), start, end); - } - - @Override - public Long count(double min, double max) { - return ops.count(getKey(), min, max); - } - - @Override - public Long lexCount(Range range) { - return ops.lexCount(getKey(), range); - } - - @Nullable - @Override - public TypedTuple popMin() { - return ops.popMin(getKey()); - } - - @Nullable - @Override - public Set> popMin(long count) { - return ops.popMin(getKey(), count); - } - - @Nullable - @Override - public TypedTuple popMin(long timeout, TimeUnit unit) { - return ops.popMin(getKey(), timeout, unit); - } - - @Nullable - @Override - public TypedTuple popMax() { - return ops.popMax(getKey()); - } - - @Nullable - @Override - public Set> popMax(long count) { - return ops.popMax(getKey(), count); - } - - @Nullable - @Override - public TypedTuple popMax(long timeout, TimeUnit unit) { - return ops.popMax(getKey(), timeout, unit); - } - - @Override - public Long size() { - return zCard(); - } - - @Override - public Long zCard() { - return ops.zCard(getKey()); - } - - @Nullable - @Override - public Set difference(Collection otherKeys) { - return ops.difference(getKey(), otherKeys); - } - - @Nullable - @Override - public Set> differenceWithScores(Collection otherKeys) { - return ops.differenceWithScores(getKey(), otherKeys); - } - - @Nullable - @Override - public Long differenceAndStore(Collection otherKeys, K destKey) { - return ops.differenceAndStore(getKey(), otherKeys, destKey); - } - - @Nullable - @Override - public Set intersect(Collection otherKeys) { - return ops.intersect(getKey(), otherKeys); - } - - @Nullable - @Override - public Set> intersectWithScores(Collection otherKeys) { - return ops.intersectWithScores(getKey(), otherKeys); - } - - @Nullable - @Override - public Set> intersectWithScores(Collection otherKeys, Aggregate aggregate, Weights weights) { - return ops.intersectWithScores(getKey(), otherKeys, aggregate, weights); - } - - @Override - public Long intersectAndStore(K otherKey, K destKey) { - return ops.intersectAndStore(getKey(), otherKey, destKey); - } - - @Override - public Long intersectAndStore(Collection otherKeys, K destKey) { - return ops.intersectAndStore(getKey(), otherKeys, destKey); - } - - @Override - public Long intersectAndStore(Collection otherKeys, K destKey, Aggregate aggregate) { - return ops.intersectAndStore(getKey(), otherKeys, destKey, aggregate); - } - - @Override - public Long intersectAndStore(Collection otherKeys, K destKey, Aggregate aggregate, Weights weights) { - return ops.intersectAndStore(getKey(), otherKeys, destKey, aggregate, weights); - } - - @Nullable - @Override - public Set union(Collection otherKeys) { - return ops.union(getKey(), otherKeys); - } - - @Nullable - @Override - public Set> unionWithScores(Collection otherKeys) { - return ops.unionWithScores(getKey(), otherKeys); - } - - @Nullable - @Override - public Set> unionWithScores(Collection otherKeys, Aggregate aggregate, Weights weights) { - return ops.unionWithScores(getKey(), otherKeys, aggregate, weights); - } - - @Override - public Long unionAndStore(K otherKey, K destKey) { - return ops.unionAndStore(getKey(), otherKey, destKey); - } - - @Override - public Long unionAndStore(Collection otherKeys, K destKey) { - return ops.unionAndStore(getKey(), otherKeys, destKey); - } - - @Override - public Long unionAndStore(Collection otherKeys, K destKey, Aggregate aggregate) { - return ops.unionAndStore(getKey(), otherKeys, destKey, aggregate); - } - - @Override - public Long unionAndStore(Collection otherKeys, K destKey, Aggregate aggregate, Weights weights) { - return ops.unionAndStore(getKey(), otherKeys, destKey, aggregate, weights); - } - - @Override - public DataType getType() { - return DataType.ZSET; - } - - @Override - public Cursor> scan(ScanOptions options) { - return ops.scan(getKey(), options); - } -} diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index cc9b4af92c..5185175848 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -105,6 +105,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation private @Nullable ScriptExecutor scriptExecutor; + private final BoundOperationsProxyFactory boundOperations = new BoundOperationsProxyFactory(); private final ValueOperations valueOps = new DefaultValueOperations<>(this); private final ListOperations listOps = new DefaultListOperations<>(this); private final SetOperations setOps = new DefaultSetOperations<>(this); @@ -1056,12 +1057,12 @@ public GeoOperations opsForGeo() { @Override public BoundGeoOperations boundGeoOps(K key) { - return new DefaultBoundGeoOperations<>(key, this); + return boundOperations.createProxy(BoundGeoOperations.class, key, DataType.ZSET, this, RedisOperations::opsForGeo); } @Override public BoundHashOperations boundHashOps(K key) { - return new DefaultBoundHashOperations<>(key, this); + return boundOperations.createProxy(BoundHashOperations.class, key, DataType.HASH, this, it -> it.opsForHash()); } @Override @@ -1081,12 +1082,13 @@ public ListOperations opsForList() { @Override public BoundListOperations boundListOps(K key) { - return new DefaultBoundListOperations<>(key, this); + return boundOperations.createProxy(BoundListOperations.class, key, DataType.LIST, this, + RedisOperations::opsForList); } @Override public BoundSetOperations boundSetOps(K key) { - return new DefaultBoundSetOperations<>(key, this); + return boundOperations.createProxy(BoundSetOperations.class, key, DataType.SET, this, RedisOperations::opsForSet); } @Override @@ -1101,18 +1103,18 @@ public StreamOperations opsForStream() { @Override public StreamOperations opsForStream(HashMapper hashMapper) { - return new DefaultStreamOperations<>(this, hashMapper); } @Override public BoundStreamOperations boundStreamOps(K key) { - return new DefaultBoundStreamOperations<>(key, this); + return boundOperations.createProxy(BoundStreamOperations.class, key, DataType.STREAM, this, it -> opsForStream()); } @Override public BoundValueOperations boundValueOps(K key) { - return new DefaultBoundValueOperations<>(key, this); + return boundOperations.createProxy(BoundValueOperations.class, key, DataType.STRING, this, + RedisOperations::opsForValue); } @Override @@ -1122,7 +1124,8 @@ public ValueOperations opsForValue() { @Override public BoundZSetOperations boundZSetOps(K key) { - return new DefaultBoundZSetOperations<>(key, this); + return boundOperations.createProxy(BoundZSetOperations.class, key, DataType.ZSET, this, + RedisOperations::opsForZSet); } @Override diff --git a/src/test/java/org/springframework/data/redis/core/BoundOperationsProxyFactoryUnitTests.java b/src/test/java/org/springframework/data/redis/core/BoundOperationsProxyFactoryUnitTests.java new file mode 100644 index 0000000000..c49e1eb40f --- /dev/null +++ b/src/test/java/org/springframework/data/redis/core/BoundOperationsProxyFactoryUnitTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 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.core; + +import static org.assertj.core.api.Assertions.*; + +import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.junit.jupiter.api.DynamicContainer; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +/** + * Unit tests for {@link BoundOperationsProxyFactory}. + * + * @author Mark Paluch + */ +class BoundOperationsProxyFactoryUnitTests { + + private void test(Class operationsTarget, BoundOperationsProxyFactory factory, Method method) { + + Method toCall = factory.lookupMethod(method, operationsTarget, true); + if (toCall == null) { + toCall = factory.lookupMethod(method, BoundOperationsProxyFactory.DefaultBoundKeyOperations.class, false); + } + + assertThat(toCall) + .describedAs("Backing method for method %s not found in %s".formatted(method, operationsTarget.getName())) + .isNotNull(); + } + + @TestFactory + Stream containers() { + + Stream, Class>> input = Stream.of( // + Tuples.of(BoundGeoOperations.class, GeoOperations.class), // + Tuples.of(BoundHashOperations.class, HashOperations.class), // + Tuples.of(BoundListOperations.class, ListOperations.class), // + Tuples.of(BoundStreamOperations.class, StreamOperations.class), // + Tuples.of(BoundSetOperations.class, SetOperations.class), // + Tuples.of(BoundValueOperations.class, ValueOperations.class), // + Tuples.of(BoundZSetOperations.class, ZSetOperations.class) // + ); + + return input.map(it -> containerFor(it.getT1(), it.getT2())); + } + + private DynamicContainer containerFor(Class boundInterface, Class operationsTarget) { + Stream methods = Arrays.stream(boundInterface.getMethods()) + .filter(it -> !it.getName().equals("getType") && !it.getName().equals("getOperations")) + .filter(Predicate.not(Method::isDefault)); + + BoundOperationsProxyFactory factory = new BoundOperationsProxyFactory(); + + Stream stream = DynamicTest.stream(methods, Method::toString, method -> { + + test(operationsTarget, factory, method); + + }); + + return DynamicContainer.dynamicContainer(boundInterface.getSimpleName(), stream); + } + +} diff --git a/src/test/java/org/springframework/data/redis/core/DefaultBoundValueOperationsUnitTests.java b/src/test/java/org/springframework/data/redis/core/DefaultBoundValueOperationsUnitTests.java deleted file mode 100644 index fee2bbd437..0000000000 --- a/src/test/java/org/springframework/data/redis/core/DefaultBoundValueOperationsUnitTests.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2018-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.core; - -import static org.mockito.Mockito.*; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; - -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.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; - -/** - * Unit tests for {@link DefaultBoundValueOperations} - * - * @author Christoph Strobl - */ -@ExtendWith(MockitoExtension.class) -@MockitoSettings(strictness = Strictness.LENIENT) -class DefaultBoundValueOperationsUnitTests { - - private DefaultBoundValueOperations boundValueOps; - - @Mock ValueOperations valueOps; - - private static final String KEY = "key-1"; - private static final Object VALUE = "value"; - - @BeforeEach - void setUp() { - - RedisOperations redisOps = mock(RedisOperations.class); - when(redisOps.opsForValue()).thenReturn(valueOps); - - boundValueOps = new DefaultBoundValueOperations<>(KEY, redisOps); - } - - @Test // DATAREDIS-786 - void setIfPresentShouldDelegateCorrectly() { - - boundValueOps.setIfPresent(VALUE); - - verify(valueOps).setIfPresent(eq(KEY), eq(VALUE)); - } - - @Test // DATAREDIS-786 - void setIfPresentWithTimeoutShouldDelegateCorrectly() { - - boundValueOps.setIfPresent(VALUE, 10, TimeUnit.SECONDS); - - verify(valueOps).setIfPresent(eq(KEY), eq(VALUE), eq(10L), eq(TimeUnit.SECONDS)); - } - - @Test // DATAREDIS-815 - void setWithDurationOfSecondsShouldDelegateCorrectly() { - - boundValueOps.set(VALUE, Duration.ofSeconds(1)); - - verify(valueOps).set(eq(KEY), eq(VALUE), eq(1L), eq(TimeUnit.SECONDS)); - } - - @Test // DATAREDIS-815 - void setWithDurationOfMillisShouldDelegateCorrectly() { - - boundValueOps.set(VALUE, Duration.ofMillis(250)); - - verify(valueOps).set(eq(KEY), eq(VALUE), eq(250L), eq(TimeUnit.MILLISECONDS)); - } - - @Test // DATAREDIS-815 - void setIfAbsentWithDurationOfSecondsShouldDelegateCorrectly() { - - boundValueOps.setIfAbsent(VALUE, Duration.ofSeconds(1)); - - verify(valueOps).setIfAbsent(eq(KEY), eq(VALUE), eq(1L), eq(TimeUnit.SECONDS)); - } - - @Test // DATAREDIS-815 - void setIfAbsentWithDurationOfMillisShouldDelegateCorrectly() { - - boundValueOps.setIfAbsent(VALUE, Duration.ofMillis(250)); - - verify(valueOps).setIfAbsent(eq(KEY), eq(VALUE), eq(250L), eq(TimeUnit.MILLISECONDS)); - } - - @Test // DATAREDIS-815 - void setIfPresentWithDurationOfSecondsShouldDelegateCorrectly() { - - boundValueOps.setIfPresent(VALUE, Duration.ofSeconds(1)); - - verify(valueOps).setIfPresent(eq(KEY), eq(VALUE), eq(1L), eq(TimeUnit.SECONDS)); - } - - @Test // DATAREDIS-815 - void setIfPresentWithDurationOfMillisShouldDelegateCorrectly() { - - boundValueOps.setIfPresent(VALUE, Duration.ofMillis(250)); - - verify(valueOps).setIfPresent(eq(KEY), eq(VALUE), eq(250L), eq(TimeUnit.MILLISECONDS)); - } -} diff --git a/src/test/java/org/springframework/data/redis/core/DefaultBoundZSetOperationsUnitTests.java b/src/test/java/org/springframework/data/redis/core/DefaultBoundZSetOperationsUnitTests.java deleted file mode 100644 index f97fa5eee2..0000000000 --- a/src/test/java/org/springframework/data/redis/core/DefaultBoundZSetOperationsUnitTests.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2021-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.core; - -import static org.mockito.ArgumentMatchers.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.data.redis.connection.RedisZSetCommands.Range; - -/** - * Unit tests for {@link DefaultBoundZSetOperations}. - * - * @author Christoph Strobl - */ -class DefaultBoundZSetOperationsUnitTests { - - DefaultBoundZSetOperations zSetOperations; - ConnectionMockingRedisTemplate template; - - @BeforeEach - void beforeEach() { - - template = ConnectionMockingRedisTemplate.template(); - zSetOperations = new DefaultBoundZSetOperations<>("key", template); - } - - @Test // GH-1816 - void delegatesRemoveRangeByLex() { - - Range range = Range.range().gte("alpha").lte("omega"); - zSetOperations.removeRangeByLex(range); - - template.verify().zRemRangeByLex(eq(template.serializeKey("key")), eq(range)); - } -} From f2f3fc2da71ce7fd6c5276255a6a3445c5c064e5 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Feb 2022 14:50:19 +0100 Subject: [PATCH 09/12] Reorder methods. --- .../data/redis/core/RedisOperations.java | 6 +- .../data/redis/core/RedisTemplate.java | 786 +++++++++--------- 2 files changed, 410 insertions(+), 382 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/core/RedisOperations.java b/src/main/java/org/springframework/data/redis/core/RedisOperations.java index 2d204b63da..0e51aff095 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -95,7 +95,7 @@ public interface RedisOperations { * values are hashes, this serializer will be used to deserialize both the key and value * @return list of objects returned by the pipeline */ - List executePipelined(final RedisCallback action, final RedisSerializer resultSerializer); + List executePipelined(RedisCallback action, RedisSerializer resultSerializer); /** * Executes the given Redis session on a pipelined connection. Allows transactions to be pipelined. Note that the @@ -104,7 +104,7 @@ public interface RedisOperations { * @param session Session callback * @return list of objects returned by the pipeline */ - List executePipelined(final SessionCallback session); + List executePipelined(SessionCallback session); /** * Executes the given Redis session on a pipelined connection, returning the results using a dedicated serializer. @@ -115,7 +115,7 @@ public interface RedisOperations { * @param resultSerializer * @return list of objects returned by the pipeline */ - List executePipelined(final SessionCallback session, final RedisSerializer resultSerializer); + List executePipelined(SessionCallback session, RedisSerializer resultSerializer); /** * Executes the given {@link RedisScript} diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 5185175848..add8f42697 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -165,6 +165,192 @@ public void afterPropertiesSet() { initialized = true; } + /** + * Returns whether to expose the native Redis connection to RedisCallback code, or rather a connection proxy (the + * default). + * + * @return whether to expose the native Redis connection or not + */ + public boolean isExposeConnection() { + return exposeConnection; + } + + /** + * Sets whether to expose the Redis connection to {@link RedisCallback} code. Default is "false": a proxy will be + * returned, suppressing {@code quit} and {@code disconnect} calls. + * + * @param exposeConnection + */ + public void setExposeConnection(boolean exposeConnection) { + this.exposeConnection = exposeConnection; + } + + /** + * @return Whether or not the default serializer should be used. If not, any serializers not explicitly set will + * remain null and values will not be serialized or deserialized. + */ + public boolean isEnableDefaultSerializer() { + return enableDefaultSerializer; + } + + /** + * @param enableDefaultSerializer Whether or not the default serializer should be used. If not, any serializers not + * explicitly set will remain null and values will not be serialized or deserialized. + */ + public void setEnableDefaultSerializer(boolean enableDefaultSerializer) { + this.enableDefaultSerializer = enableDefaultSerializer; + } + + /** + * If set to {@code true} {@link RedisTemplate} will participate in ongoing transactions using + * {@literal MULTI...EXEC|DISCARD} to keep track of operations. + * + * @param enableTransactionSupport whether to participate in ongoing transactions. + * @since 1.3 + * @see RedisConnectionUtils#getConnection(RedisConnectionFactory, boolean) + * @see TransactionSynchronizationManager#isActualTransactionActive() + */ + public void setEnableTransactionSupport(boolean enableTransactionSupport) { + this.enableTransactionSupport = enableTransactionSupport; + } + + /** + * Set the {@link ClassLoader} to be used for the default {@link JdkSerializationRedisSerializer} in case no other + * {@link RedisSerializer} is explicitly set as the default one. + * + * @param classLoader can be {@literal null}. + * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader + * @since 1.8 + */ + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Returns the default serializer used by this template. + * + * @return template default serializer + */ + @Nullable + public RedisSerializer getDefaultSerializer() { + return defaultSerializer; + } + + /** + * Sets the default serializer to use for this template. All serializers (except the + * {@link #setStringSerializer(RedisSerializer)}) are initialized to this value unless explicitly set. Defaults to + * {@link JdkSerializationRedisSerializer}. + * + * @param serializer default serializer to use + */ + public void setDefaultSerializer(RedisSerializer serializer) { + this.defaultSerializer = serializer; + } + + /** + * Sets the key serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. + * + * @param serializer the key serializer to be used by this template. + */ + public void setKeySerializer(RedisSerializer serializer) { + this.keySerializer = serializer; + } + + /** + * Returns the key serializer used by this template. + * + * @return the key serializer used by this template. + */ + @Override + public RedisSerializer getKeySerializer() { + return keySerializer; + } + + /** + * Sets the value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. + * + * @param serializer the value serializer to be used by this template. + */ + public void setValueSerializer(RedisSerializer serializer) { + this.valueSerializer = serializer; + } + + /** + * Returns the value serializer used by this template. + * + * @return the value serializer used by this template. + */ + @Override + public RedisSerializer getValueSerializer() { + return valueSerializer; + } + + /** + * Returns the hashKeySerializer. + * + * @return Returns the hashKeySerializer + */ + @Override + public RedisSerializer getHashKeySerializer() { + return hashKeySerializer; + } + + /** + * Sets the hash key (or field) serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. + * + * @param hashKeySerializer The hashKeySerializer to set. + */ + public void setHashKeySerializer(RedisSerializer hashKeySerializer) { + this.hashKeySerializer = hashKeySerializer; + } + + /** + * Returns the hashValueSerializer. + * + * @return Returns the hashValueSerializer + */ + @Override + public RedisSerializer getHashValueSerializer() { + return hashValueSerializer; + } + + /** + * Sets the hash value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. + * + * @param hashValueSerializer The hashValueSerializer to set. + */ + public void setHashValueSerializer(RedisSerializer hashValueSerializer) { + this.hashValueSerializer = hashValueSerializer; + } + + /** + * Returns the stringSerializer. + * + * @return Returns the stringSerializer + */ + public RedisSerializer getStringSerializer() { + return stringSerializer; + } + + /** + * Sets the string value serializer to be used by this template (when the arguments or return types are always + * strings). Defaults to {@link StringRedisSerializer}. + * + * @see ValueOperations#get(Object, long, long) + * @param stringSerializer The stringValueSerializer to set. + */ + public void setStringSerializer(RedisSerializer stringSerializer) { + this.stringSerializer = stringSerializer; + } + + /** + * @param scriptExecutor The {@link ScriptExecutor} to use for executing Redis scripts + */ + public void setScriptExecutor(ScriptExecutor scriptExecutor) { + this.scriptExecutor = scriptExecutor; + } + @Override @Nullable public T execute(RedisCallback action) { @@ -361,316 +547,26 @@ protected T postProcessResult(@Nullable T result, RedisConnection conn, bool return result; } - /** - * Returns whether to expose the native Redis connection to RedisCallback code, or rather a connection proxy (the - * default). - * - * @return whether to expose the native Redis connection or not - */ - public boolean isExposeConnection() { - return exposeConnection; - } + // ------------------------------------------------------------------------- + // Methods dealing with Redis Keys + // ------------------------------------------------------------------------- - /** - * Sets whether to expose the Redis connection to {@link RedisCallback} code. Default is "false": a proxy will be - * returned, suppressing {@code quit} and {@code disconnect} calls. - * - * @param exposeConnection - */ - public void setExposeConnection(boolean exposeConnection) { - this.exposeConnection = exposeConnection; - } + @Override + public Boolean copy(K source, K target, boolean replace) { - /** - * @return Whether or not the default serializer should be used. If not, any serializers not explicitly set will - * remain null and values will not be serialized or deserialized. - */ - public boolean isEnableDefaultSerializer() { - return enableDefaultSerializer; - } + byte[] sourceKey = rawKey(source); + byte[] targetKey = rawKey(target); - /** - * @param enableDefaultSerializer Whether or not the default serializer should be used. If not, any serializers not - * explicitly set will remain null and values will not be serialized or deserialized. - */ - public void setEnableDefaultSerializer(boolean enableDefaultSerializer) { - this.enableDefaultSerializer = enableDefaultSerializer; + return execute(connection -> connection.copy(sourceKey, targetKey, replace), true); } - /** - * Returns the default serializer used by this template. - * - * @return template default serializer - */ - @Nullable - public RedisSerializer getDefaultSerializer() { - return defaultSerializer; - } + @Override + public Boolean delete(K key) { - /** - * Sets the default serializer to use for this template. All serializers (except the - * {@link #setStringSerializer(RedisSerializer)}) are initialized to this value unless explicitly set. Defaults to - * {@link JdkSerializationRedisSerializer}. - * - * @param serializer default serializer to use - */ - public void setDefaultSerializer(RedisSerializer serializer) { - this.defaultSerializer = serializer; - } + byte[] rawKey = rawKey(key); - /** - * Sets the key serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. - * - * @param serializer the key serializer to be used by this template. - */ - public void setKeySerializer(RedisSerializer serializer) { - this.keySerializer = serializer; - } - - /** - * Returns the key serializer used by this template. - * - * @return the key serializer used by this template. - */ - @Override - public RedisSerializer getKeySerializer() { - return keySerializer; - } - - /** - * Sets the value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. - * - * @param serializer the value serializer to be used by this template. - */ - public void setValueSerializer(RedisSerializer serializer) { - this.valueSerializer = serializer; - } - - /** - * Returns the value serializer used by this template. - * - * @return the value serializer used by this template. - */ - @Override - public RedisSerializer getValueSerializer() { - return valueSerializer; - } - - /** - * Returns the hashKeySerializer. - * - * @return Returns the hashKeySerializer - */ - @Override - public RedisSerializer getHashKeySerializer() { - return hashKeySerializer; - } - - /** - * Sets the hash key (or field) serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. - * - * @param hashKeySerializer The hashKeySerializer to set. - */ - public void setHashKeySerializer(RedisSerializer hashKeySerializer) { - this.hashKeySerializer = hashKeySerializer; - } - - /** - * Returns the hashValueSerializer. - * - * @return Returns the hashValueSerializer - */ - @Override - public RedisSerializer getHashValueSerializer() { - return hashValueSerializer; - } - - /** - * Sets the hash value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}. - * - * @param hashValueSerializer The hashValueSerializer to set. - */ - public void setHashValueSerializer(RedisSerializer hashValueSerializer) { - this.hashValueSerializer = hashValueSerializer; - } - - /** - * Returns the stringSerializer. - * - * @return Returns the stringSerializer - */ - public RedisSerializer getStringSerializer() { - return stringSerializer; - } - - /** - * Sets the string value serializer to be used by this template (when the arguments or return types are always - * strings). Defaults to {@link StringRedisSerializer}. - * - * @see ValueOperations#get(Object, long, long) - * @param stringSerializer The stringValueSerializer to set. - */ - public void setStringSerializer(RedisSerializer stringSerializer) { - this.stringSerializer = stringSerializer; - } - - /** - * @param scriptExecutor The {@link ScriptExecutor} to use for executing Redis scripts - */ - public void setScriptExecutor(ScriptExecutor scriptExecutor) { - this.scriptExecutor = scriptExecutor; - } - - @SuppressWarnings("unchecked") - private byte[] rawKey(Object key) { - Assert.notNull(key, "non null key required"); - if (keySerializer == null && key instanceof byte[]) { - return (byte[]) key; - } - return keySerializer.serialize(key); - } - - private byte[] rawString(String key) { - return stringSerializer.serialize(key); - } - - @SuppressWarnings("unchecked") - private byte[] rawValue(Object value) { - if (valueSerializer == null && value instanceof byte[]) { - return (byte[]) value; - } - return valueSerializer.serialize(value); - } - - private byte[][] rawKeys(Collection keys) { - final byte[][] rawKeys = new byte[keys.size()][]; - - int i = 0; - for (K key : keys) { - rawKeys[i++] = rawKey(key); - } - - return rawKeys; - } - - @SuppressWarnings("unchecked") - private K deserializeKey(byte[] value) { - return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Nullable - private List deserializeMixedResults(@Nullable List rawValues, - @Nullable RedisSerializer valueSerializer, @Nullable RedisSerializer hashKeySerializer, - @Nullable RedisSerializer hashValueSerializer) { - - if (rawValues == null) { - return null; - } - - List values = new ArrayList<>(); - for (Object rawValue : rawValues) { - - if (rawValue instanceof byte[] && valueSerializer != null) { - values.add(valueSerializer.deserialize((byte[]) rawValue)); - } else if (rawValue instanceof List) { - // Lists are the only potential Collections of mixed values.... - values.add(deserializeMixedResults((List) rawValue, valueSerializer, hashKeySerializer, hashValueSerializer)); - } else if (rawValue instanceof Set && !(((Set) rawValue).isEmpty())) { - values.add(deserializeSet((Set) rawValue, valueSerializer)); - } else if (rawValue instanceof Map && !(((Map) rawValue).isEmpty()) - && ((Map) rawValue).values().iterator().next() instanceof byte[]) { - values.add(SerializationUtils.deserialize((Map) rawValue, hashKeySerializer, hashValueSerializer)); - } else { - values.add(rawValue); - } - } - - return values; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Set deserializeSet(Set rawSet, @Nullable RedisSerializer valueSerializer) { - - if (rawSet.isEmpty()) { - return rawSet; - } - - Object setValue = rawSet.iterator().next(); - - if (setValue instanceof byte[] && valueSerializer != null) { - return (SerializationUtils.deserialize(rawSet, valueSerializer)); - } else if (setValue instanceof Tuple) { - return convertTupleValues(rawSet, valueSerializer); - } else { - return rawSet; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private Set> convertTupleValues(Set rawValues, @Nullable RedisSerializer valueSerializer) { - - Set> set = new LinkedHashSet<>(rawValues.size()); - for (Tuple rawValue : rawValues) { - Object value = rawValue.getValue(); - if (valueSerializer != null) { - value = valueSerializer.deserialize(rawValue.getValue()); - } - set.add(new DefaultTypedTuple(value, rawValue.getScore())); - } - return set; - } - - // - // RedisOperations - // - - /** - * Execute a transaction, using the default {@link RedisSerializer}s to deserialize any results that are byte[]s or - * Collections or Maps of byte[]s or Tuples. Other result types (Long, Boolean, etc) are left as-is in the converted - * results. If conversion of tx results has been disabled in the {@link RedisConnectionFactory}, the results of exec - * will be returned without deserialization. This check is mostly for backwards compatibility with 1.0. - * - * @return The (possibly deserialized) results of transaction exec - */ - @Override - public List exec() { - - List results = execRaw(); - if (getRequiredConnectionFactory().getConvertPipelineAndTxResults()) { - return deserializeMixedResults(results, valueSerializer, hashKeySerializer, hashValueSerializer); - } else { - return results; - } - } - - @Override - public List exec(RedisSerializer valueSerializer) { - return deserializeMixedResults(execRaw(), valueSerializer, valueSerializer, valueSerializer); - } - - protected List execRaw() { - - List raw = execute(RedisTxCommands::exec); - return raw == null ? Collections.emptyList() : raw; - } - - @Override - public Boolean copy(K source, K target, boolean replace) { - - byte[] sourceKey = rawKey(source); - byte[] targetKey = rawKey(target); - - return execute(connection -> connection.copy(sourceKey, targetKey, replace), true); - } - - @Override - public Boolean delete(K key) { - - byte[] rawKey = rawKey(key); - - Long result = execute(connection -> connection.del(rawKey), true); - return result != null && result.intValue() == 1; + Long result = execute(connection -> connection.del(rawKey), true); + return result != null && result.intValue() == 1; } @Override @@ -899,54 +795,6 @@ public void restore(K key, final byte[] value, long timeToLive, TimeUnit unit, b }, true); } - @Override - public void multi() { - execute(connection -> { - connection.multi(); - return null; - }, true); - } - - @Override - public void discard() { - - execute(connection -> { - connection.discard(); - return null; - }, true); - } - - @Override - public void watch(K key) { - - byte[] rawKey = rawKey(key); - - execute(connection -> { - connection.watch(rawKey); - return null; - }, true); - } - - @Override - public void watch(Collection keys) { - - byte[][] rawKeys = rawKeys(keys); - - execute(connection -> { - connection.watch(rawKeys); - return null; - }, true); - } - - @Override - public void unwatch() { - - execute(connection -> { - connection.unwatch(); - return null; - }, true); - } - // Sort operations @Override @@ -1006,28 +854,115 @@ public Long sort(SortQuery query, K storeKey) { byte[] rawKey = rawKey(query.getKey()); SortParameters params = QueryUtils.convertQuery(query, stringSerializer); - return execute(connection -> connection.sort(rawKey, params, rawStoreKey), true); + return doWithKeys(connection -> connection.sort(rawKey, params, rawStoreKey)); } + // ------------------------------------------------------------------------- + // Methods dealing with Redis Transactions + // ------------------------------------------------------------------------- + + @Override - public void killClient(final String host, final int port) { + public void watch(K key) { - execute((RedisCallback) connection -> { - connection.killClient(host, port); + byte[] rawKey = rawKey(key); + + execute(connection -> { + connection.watch(rawKey); return null; - }); + }, true); + } + + @Override + public void watch(Collection keys) { + + byte[][] rawKeys = rawKeys(keys); + + execute(connection -> { + connection.watch(rawKeys); + return null; + }, true); + } + + @Override + public void unwatch() { + + execute(connection -> { + connection.unwatch(); + return null; + }, true); + } + + @Override + public void multi() { + execute(connection -> { + connection.multi(); + return null; + }, true); + } + + @Override + public void discard() { + + execute(connection -> { + connection.discard(); + return null; + }, true); + } + + /** + * Execute a transaction, using the default {@link RedisSerializer}s to deserialize any results that are byte[]s or + * Collections or Maps of byte[]s or Tuples. Other result types (Long, Boolean, etc) are left as-is in the converted + * results. If conversion of tx results has been disabled in the {@link RedisConnectionFactory}, the results of exec + * will be returned without deserialization. This check is mostly for backwards compatibility with 1.0. + * + * @return The (possibly deserialized) results of transaction exec + */ + @Override + public List exec() { + + List results = execRaw(); + if (getRequiredConnectionFactory().getConvertPipelineAndTxResults()) { + return deserializeMixedResults(results, valueSerializer, hashKeySerializer, hashValueSerializer); + } else { + return results; + } + } + + @Override + public List exec(RedisSerializer valueSerializer) { + return deserializeMixedResults(execRaw(), valueSerializer, valueSerializer, valueSerializer); + } + + protected List execRaw() { + + List raw = execute(RedisTxCommands::exec); + return raw == null ? Collections.emptyList() : raw; } + // ------------------------------------------------------------------------- + // Methods dealing with Redis Server Commands + // ------------------------------------------------------------------------- + @Override public List getClientList() { return execute(RedisServerCommands::getClientList); } + @Override + public void killClient(String host, int port) { + + execute((RedisCallback) connection -> { + connection.killClient(host, port); + return null; + }); + } + /* * @see org.springframework.data.redis.core.RedisOperations#replicaOf(java.lang.String, int) */ @Override - public void replicaOf(final String host, final int port) { + public void replicaOf(String host, int port) { execute((RedisCallback) connection -> { @@ -1045,6 +980,24 @@ public void replicaOfNoOne() { }); } + @Override + public void convertAndSend(String channel, Object message) { + + Assert.hasText(channel, "a non-empty channel is required"); + + byte[] rawChannel = rawString(channel); + byte[] rawMessage = rawValue(message); + + execute(connection -> { + connection.publish(rawChannel, rawMessage); + return null; + }, true); + } + + // ------------------------------------------------------------------------- + // Methods to obtain specific operations interface objects. + // ------------------------------------------------------------------------- + @Override public ClusterOperations opsForCluster() { return clusterOps; @@ -1133,29 +1086,104 @@ public ZSetOperations opsForZSet() { return zSetOps; } - /** - * If set to {@code true} {@link RedisTemplate} will participate in ongoing transactions using - * {@literal MULTI...EXEC|DISCARD} to keep track of operations. - * - * @param enableTransactionSupport whether to participate in ongoing transactions. - * @since 1.3 - * @see RedisConnectionUtils#getConnection(RedisConnectionFactory, boolean) - * @see TransactionSynchronizationManager#isActualTransactionActive() - */ - public void setEnableTransactionSupport(boolean enableTransactionSupport) { - this.enableTransactionSupport = enableTransactionSupport; + @SuppressWarnings("unchecked") + private byte[] rawKey(Object key) { + Assert.notNull(key, "non null key required"); + if (keySerializer == null && key instanceof byte[]) { + return (byte[]) key; + } + return keySerializer.serialize(key); } - /** - * Set the {@link ClassLoader} to be used for the default {@link JdkSerializationRedisSerializer} in case no other - * {@link RedisSerializer} is explicitly set as the default one. - * - * @param classLoader can be {@literal null}. - * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader - * @since 1.8 - */ - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; + private byte[] rawString(String key) { + return stringSerializer.serialize(key); + } + + @SuppressWarnings("unchecked") + private byte[] rawValue(Object value) { + if (valueSerializer == null && value instanceof byte[]) { + return (byte[]) value; + } + return valueSerializer.serialize(value); + } + + private byte[][] rawKeys(Collection keys) { + final byte[][] rawKeys = new byte[keys.size()][]; + + int i = 0; + for (K key : keys) { + rawKeys[i++] = rawKey(key); + } + + return rawKeys; + } + + @SuppressWarnings("unchecked") + private K deserializeKey(byte[] value) { + return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value; } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Nullable + private List deserializeMixedResults(@Nullable List rawValues, + @Nullable RedisSerializer valueSerializer, @Nullable RedisSerializer hashKeySerializer, + @Nullable RedisSerializer hashValueSerializer) { + + if (rawValues == null) { + return null; + } + + List values = new ArrayList<>(); + for (Object rawValue : rawValues) { + + if (rawValue instanceof byte[] && valueSerializer != null) { + values.add(valueSerializer.deserialize((byte[]) rawValue)); + } else if (rawValue instanceof List) { + // Lists are the only potential Collections of mixed values.... + values.add(deserializeMixedResults((List) rawValue, valueSerializer, hashKeySerializer, hashValueSerializer)); + } else if (rawValue instanceof Set && !(((Set) rawValue).isEmpty())) { + values.add(deserializeSet((Set) rawValue, valueSerializer)); + } else if (rawValue instanceof Map && !(((Map) rawValue).isEmpty()) + && ((Map) rawValue).values().iterator().next() instanceof byte[]) { + values.add(SerializationUtils.deserialize((Map) rawValue, hashKeySerializer, hashValueSerializer)); + } else { + values.add(rawValue); + } + } + + return values; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Set deserializeSet(Set rawSet, @Nullable RedisSerializer valueSerializer) { + + if (rawSet.isEmpty()) { + return rawSet; + } + + Object setValue = rawSet.iterator().next(); + + if (setValue instanceof byte[] && valueSerializer != null) { + return (SerializationUtils.deserialize(rawSet, valueSerializer)); + } else if (setValue instanceof Tuple) { + return convertTupleValues(rawSet, valueSerializer); + } else { + return rawSet; + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private Set> convertTupleValues(Set rawValues, @Nullable RedisSerializer valueSerializer) { + + Set> set = new LinkedHashSet<>(rawValues.size()); + for (Tuple rawValue : rawValues) { + Object value = rawValue.getValue(); + if (valueSerializer != null) { + value = valueSerializer.deserialize(rawValue.getValue()); + } + set.add(new DefaultTypedTuple(value, rawValue.getScore())); + } + return set; + } + } From 4d1c188f2a768f5e1a5bc085b902f144aa992ea3 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Feb 2022 15:00:02 +0100 Subject: [PATCH 10/12] Introduce doWithKeys. --- .../data/redis/core/RedisTemplate.java | 103 ++++++++++-------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index add8f42697..27b7f9ec2e 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -551,13 +552,27 @@ protected T postProcessResult(@Nullable T result, RedisConnection conn, bool // Methods dealing with Redis Keys // ------------------------------------------------------------------------- + @Override + public void convertAndSend(String channel, Object message) { + + Assert.hasText(channel, "a non-empty channel is required"); + + byte[] rawChannel = rawString(channel); + byte[] rawMessage = rawValue(message); + + execute(connection -> { + connection.publish(rawChannel, rawMessage); + return null; + }, true); + } + @Override public Boolean copy(K source, K target, boolean replace) { byte[] sourceKey = rawKey(source); byte[] targetKey = rawKey(target); - return execute(connection -> connection.copy(sourceKey, targetKey, replace), true); + return doWithKeys(connection -> connection.copy(sourceKey, targetKey, replace)); } @Override @@ -565,7 +580,7 @@ public Boolean delete(K key) { byte[] rawKey = rawKey(key); - Long result = execute(connection -> connection.del(rawKey), true); + Long result = doWithKeys(connection -> connection.del(rawKey)); return result != null && result.intValue() == 1; } @@ -578,7 +593,7 @@ public Long delete(Collection keys) { byte[][] rawKeys = rawKeys(keys); - return execute(connection -> connection.del(rawKeys), true); + return doWithKeys(connection -> connection.del(rawKeys)); } @Override @@ -586,7 +601,7 @@ public Boolean unlink(K key) { byte[] rawKey = rawKey(key); - Long result = execute(connection -> connection.unlink(rawKey), true); + Long result = doWithKeys(connection -> connection.unlink(rawKey)); return result != null && result.intValue() == 1; } @@ -600,7 +615,7 @@ public Long unlink(Collection keys) { byte[][] rawKeys = rawKeys(keys); - return execute(connection -> connection.unlink(rawKeys), true); + return doWithKeys(connection -> connection.unlink(rawKeys)); } @Override @@ -608,7 +623,7 @@ public Boolean hasKey(K key) { byte[] rawKey = rawKey(key); - return execute(connection -> connection.exists(rawKey), true); + return doWithKeys(connection -> connection.exists(rawKey)); } @Override @@ -617,7 +632,7 @@ public Long countExistingKeys(Collection keys) { Assert.notNull(keys, "Keys must not be null!"); byte[][] rawKeys = rawKeys(keys); - return execute(connection -> connection.exists(rawKeys), true); + return doWithKeys(connection -> connection.exists(rawKeys)); } @Override @@ -626,14 +641,14 @@ public Boolean expire(K key, final long timeout, final TimeUnit unit) { byte[] rawKey = rawKey(key); long rawTimeout = TimeoutUtils.toMillis(timeout, unit); - return execute(connection -> { + return doWithKeys(connection -> { try { return connection.pExpire(rawKey, rawTimeout); } catch (Exception e) { // Driver may not support pExpire or we may be running on Redis 2.4 return connection.expire(rawKey, TimeoutUtils.toSeconds(timeout, unit)); } - }, true); + }); } @Override @@ -641,52 +656,38 @@ public Boolean expireAt(K key, final Date date) { byte[] rawKey = rawKey(key); - return execute(connection -> { + return doWithKeys(connection -> { try { return connection.pExpireAt(rawKey, date.getTime()); } catch (Exception e) { return connection.expireAt(rawKey, date.getTime() / 1000); } - }, true); - } - - @Override - public void convertAndSend(String channel, Object message) { - - Assert.hasText(channel, "a non-empty channel is required"); - - byte[] rawChannel = rawString(channel); - byte[] rawMessage = rawValue(message); - - execute(connection -> { - connection.publish(rawChannel, rawMessage); - return null; - }, true); + }); } - // - // Value operations - // + // ------------------------------------------------------------------------- + // Methods dealing with value operations + // ------------------------------------------------------------------------- @Override public Long getExpire(K key) { byte[] rawKey = rawKey(key); - return execute(connection -> connection.ttl(rawKey), true); + return doWithKeys(connection -> connection.ttl(rawKey)); } @Override public Long getExpire(K key, final TimeUnit timeUnit) { byte[] rawKey = rawKey(key); - return execute(connection -> { + return doWithKeys(connection -> { try { return connection.pTtl(rawKey, timeUnit); } catch (Exception e) { // Driver may not support pTtl or we may be running on Redis 2.4 return connection.ttl(rawKey, timeUnit); } - }, true); + }); } @Override @@ -694,7 +695,7 @@ public Long getExpire(K key, final TimeUnit timeUnit) { public Set keys(K pattern) { byte[] rawKey = rawKey(pattern); - Set rawKeys = execute(connection -> connection.keys(rawKey), true); + Set rawKeys = doWithKeys(connection -> connection.keys(rawKey)); return keySerializer != null ? SerializationUtils.deserialize(rawKeys, keySerializer) : (Set) rawKeys; } @@ -712,20 +713,20 @@ public Cursor scan(ScanOptions options) { public Boolean persist(K key) { byte[] rawKey = rawKey(key); - return execute(connection -> connection.persist(rawKey), true); + return doWithKeys(connection -> connection.persist(rawKey)); } @Override public Boolean move(K key, final int dbIndex) { byte[] rawKey = rawKey(key); - return execute(connection -> connection.move(rawKey, dbIndex), true); + return doWithKeys(connection -> connection.move(rawKey, dbIndex)); } @Override public K randomKey() { - byte[] rawKey = execute(RedisKeyCommands::randomKey, true); + byte[] rawKey = doWithKeys(RedisKeyCommands::randomKey); return deserializeKey(rawKey); } @@ -735,10 +736,10 @@ public void rename(K oldKey, K newKey) { byte[] rawOldKey = rawKey(oldKey); byte[] rawNewKey = rawKey(newKey); - execute(connection -> { + doWithKeys(connection -> { connection.rename(rawOldKey, rawNewKey); return null; - }, true); + }); } @Override @@ -746,14 +747,14 @@ public Boolean renameIfAbsent(K oldKey, K newKey) { byte[] rawOldKey = rawKey(oldKey); byte[] rawNewKey = rawKey(newKey); - return execute(connection -> connection.renameNX(rawOldKey, rawNewKey), true); + return doWithKeys(connection -> connection.renameNX(rawOldKey, rawNewKey)); } @Override public DataType type(K key) { byte[] rawKey = rawKey(key); - return execute(connection -> connection.type(rawKey), true); + return doWithKeys(connection -> connection.type(rawKey)); } /** @@ -768,7 +769,7 @@ public DataType type(K key) { public byte[] dump(K key) { byte[] rawKey = rawKey(key); - return execute(connection -> connection.dump(rawKey), true); + return doWithKeys(connection -> connection.dump(rawKey)); } /** @@ -784,18 +785,26 @@ public byte[] dump(K key) { * {@literal false}. */ @Override - public void restore(K key, final byte[] value, long timeToLive, TimeUnit unit, boolean replace) { + public void restore(K key, byte[] value, long timeToLive, TimeUnit unit, boolean replace) { byte[] rawKey = rawKey(key); long rawTimeout = TimeoutUtils.toMillis(timeToLive, unit); - execute(connection -> { + doWithKeys(connection -> { connection.restore(rawKey, rawTimeout, value, replace); return null; - }, true); + }); + } + + @Nullable + private T doWithKeys(Function action) { + return execute((RedisCallback) connection -> action.apply(connection.keyCommands()), true); } - // Sort operations + + // ------------------------------------------------------------------------- + // Methods dealing with sorting + // ------------------------------------------------------------------------- @Override @SuppressWarnings("unchecked") @@ -809,7 +818,7 @@ public List sort(SortQuery query, @Nullable RedisSerializer resultS byte[] rawKey = rawKey(query.getKey()); SortParameters params = QueryUtils.convertQuery(query, stringSerializer); - List vals = execute(connection -> connection.sort(rawKey, params), true); + List vals = doWithKeys(connection -> connection.sort(rawKey, params)); return SerializationUtils.deserialize(vals, resultSerializer); } @@ -858,10 +867,9 @@ public Long sort(SortQuery query, K storeKey) { } // ------------------------------------------------------------------------- - // Methods dealing with Redis Transactions + // Methods dealing with Transactions // ------------------------------------------------------------------------- - @Override public void watch(K key) { @@ -893,6 +901,7 @@ public void unwatch() { }, true); } + @Override public void multi() { execute(connection -> { From fdc8e5c3e582e0a8be3f2228feb7c9a844997065 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Feb 2022 15:10:30 +0100 Subject: [PATCH 11/12] =?UTF-8?q?Introduce=20executeWithoutResult(?= =?UTF-8?q?=E2=80=A6)=20method.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/redis/core/RedisTemplate.java | 71 +++++-------------- .../AbstractRedisCollectionUnitTests.java | 3 +- 2 files changed, 18 insertions(+), 56 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 27b7f9ec2e..30e491b682 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.function.Function; import org.springframework.beans.factory.BeanClassLoaderAware; @@ -552,20 +553,6 @@ protected T postProcessResult(@Nullable T result, RedisConnection conn, bool // Methods dealing with Redis Keys // ------------------------------------------------------------------------- - @Override - public void convertAndSend(String channel, Object message) { - - Assert.hasText(channel, "a non-empty channel is required"); - - byte[] rawChannel = rawString(channel); - byte[] rawMessage = rawValue(message); - - execute(connection -> { - connection.publish(rawChannel, rawMessage); - return null; - }, true); - } - @Override public Boolean copy(K source, K target, boolean replace) { @@ -801,7 +788,6 @@ private T doWithKeys(Function action) { return execute((RedisCallback) connection -> action.apply(connection.keyCommands()), true); } - // ------------------------------------------------------------------------- // Methods dealing with sorting // ------------------------------------------------------------------------- @@ -875,10 +861,7 @@ public void watch(K key) { byte[] rawKey = rawKey(key); - execute(connection -> { - connection.watch(rawKey); - return null; - }, true); + executeWithoutResult(connection -> connection.watch(rawKey)); } @Override @@ -886,37 +869,23 @@ public void watch(Collection keys) { byte[][] rawKeys = rawKeys(keys); - execute(connection -> { - connection.watch(rawKeys); - return null; - }, true); + executeWithoutResult(connection -> connection.watch(rawKeys)); } @Override public void unwatch() { - execute(connection -> { - connection.unwatch(); - return null; - }, true); + executeWithoutResult(RedisTxCommands::unwatch); } - @Override public void multi() { - execute(connection -> { - connection.multi(); - return null; - }, true); + executeWithoutResult(RedisTxCommands::multi); } @Override public void discard() { - - execute(connection -> { - connection.discard(); - return null; - }, true); + executeWithoutResult(RedisTxCommands::discard); } /** @@ -960,11 +929,7 @@ public List getClientList() { @Override public void killClient(String host, int port) { - - execute((RedisCallback) connection -> { - connection.killClient(host, port); - return null; - }); + executeWithoutResult(connection -> connection.killClient(host, port)); } /* @@ -972,21 +937,12 @@ public void killClient(String host, int port) { */ @Override public void replicaOf(String host, int port) { - - execute((RedisCallback) connection -> { - - connection.replicaOf(host, port); - return null; - }); + executeWithoutResult(connection -> connection.replicaOf(host, port)); } @Override public void replicaOfNoOne() { - - execute((RedisCallback) connection -> { - connection.replicaOfNoOne(); - return null; - }); + executeWithoutResult(RedisServerCommands::replicaOfNoOne); } @Override @@ -997,8 +953,13 @@ public void convertAndSend(String channel, Object message) { byte[] rawChannel = rawString(channel); byte[] rawMessage = rawValue(message); - execute(connection -> { - connection.publish(rawChannel, rawMessage); + executeWithoutResult(connection -> connection.publish(rawChannel, rawMessage)); + } + + private void executeWithoutResult(Consumer action) { + execute(it -> { + + action.accept(it); return null; }, true); } diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisCollectionUnitTests.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisCollectionUnitTests.java index 2d06295727..d9c1d8dc1b 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisCollectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisCollectionUnitTests.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; @@ -46,7 +47,7 @@ class AbstractRedisCollectionUnitTests { @SuppressWarnings("rawtypes")// private RedisTemplate redisTemplateSpy; private @Mock RedisConnectionFactory connectionFactoryMock; - private @Mock RedisConnection connectionMock; + private @Mock(answer = Answers.RETURNS_MOCKS) RedisConnection connectionMock; @SuppressWarnings({ "unchecked", "rawtypes" }) @BeforeEach From 71a0b4e0be57f03f1ce3bfd93fa34d08a61f9ef8 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 24 Feb 2022 15:25:04 +0100 Subject: [PATCH 12/12] Polishing. Tweak Javadoc. Make tests less strict for random values test. --- .../lettuce/LettuceConnectionFactory.java | 9 +- .../data/redis/core/RedisOperations.java | 42 +++--- .../data/redis/core/RedisTemplate.java | 136 +++++++++--------- .../StreamMessageListenerContainer.java | 3 +- 4 files changed, 92 insertions(+), 98 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index e84bcc244d..38f439348c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -71,10 +71,11 @@ * {@link LettuceConnection}s share a single thread-safe native connection by default. *

* The shared native connection is never closed by {@link LettuceConnection}, therefore it is not validated by default - * on {@link #getConnection()}. Use {@link #setValidateConnection(boolean)} to change this behavior if necessary. Inject - * a {@link Pool} to pool dedicated connections. If shareNativeConnection is true, the pool will be used to select a - * connection for blocking and tx operations only, which should not share a connection. If native connection sharing is - * disabled, the selected connection will be used for all operations. + * on {@link #getConnection()}. Use {@link #setValidateConnection(boolean)} to change this behavior if necessary. If + * {@code shareNativeConnection} is {@literal true}, a shared connection will be used for regular operations and a + * {@link LettuceConnectionProvider} will be used to select a connection for blocking and tx operations only, which + * should not share a connection. If native connection sharing is disabled, new (or pooled) connections will be used for + * all operations. *

* {@link LettuceConnectionFactory} should be configured using an environmental configuration and the * {@link LettuceConnectionFactory client configuration}. Lettuce supports the following environmental configurations: diff --git a/src/main/java/org/springframework/data/redis/core/RedisOperations.java b/src/main/java/org/springframework/data/redis/core/RedisOperations.java index 0e51aff095..a013ca3a42 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -195,7 +195,6 @@ T execute(RedisScript script, RedisSerializer argsSerializer, RedisSer @Nullable Long countExistingKeys(Collection keys); - /** * Delete given {@code key}. * @@ -367,6 +366,26 @@ default Boolean expireAt(K key, Instant expireAt) { @Nullable Boolean persist(K key); + /** + * Get the time to live for {@code key} in seconds. + * + * @param key must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @see Redis Documentation: TTL + */ + @Nullable + Long getExpire(K key); + + /** + * Get the time to live for {@code key} in and convert it to the given {@link TimeUnit}. + * + * @param key must not be {@literal null}. + * @param timeUnit must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 1.8 + */ + @Nullable + Long getExpire(K key, TimeUnit timeUnit); /** * Move given {@code key} to database with {@code index}. * @@ -414,27 +433,6 @@ default void restore(K key, byte[] value, long timeToLive, TimeUnit unit) { */ void restore(K key, byte[] value, long timeToLive, TimeUnit unit, boolean replace); - /** - * Get the time to live for {@code key} in seconds. - * - * @param key must not be {@literal null}. - * @return {@literal null} when used in pipeline / transaction. - * @see Redis Documentation: TTL - */ - @Nullable - Long getExpire(K key); - - /** - * Get the time to live for {@code key} in and convert it to the given {@link TimeUnit}. - * - * @param key must not be {@literal null}. - * @param timeUnit must not be {@literal null}. - * @return {@literal null} when used in pipeline / transaction. - * @since 1.8 - */ - @Nullable - Long getExpire(K key, TimeUnit timeUnit); - /** * Sort the elements for {@code query}. * diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 30e491b682..fe665c6489 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -562,6 +562,23 @@ public Boolean copy(K source, K target, boolean replace) { return doWithKeys(connection -> connection.copy(sourceKey, targetKey, replace)); } + @Override + public Boolean hasKey(K key) { + + byte[] rawKey = rawKey(key); + + return doWithKeys(connection -> connection.exists(rawKey)); + } + + @Override + public Long countExistingKeys(Collection keys) { + + Assert.notNull(keys, "Keys must not be null!"); + + byte[][] rawKeys = rawKeys(keys); + return doWithKeys(connection -> connection.exists(rawKeys)); + } + @Override public Boolean delete(K key) { @@ -606,20 +623,56 @@ public Long unlink(Collection keys) { } @Override - public Boolean hasKey(K key) { + public DataType type(K key) { byte[] rawKey = rawKey(key); + return doWithKeys(connection -> connection.type(rawKey)); + } - return doWithKeys(connection -> connection.exists(rawKey)); + @Override + @SuppressWarnings("unchecked") + public Set keys(K pattern) { + + byte[] rawKey = rawKey(pattern); + Set rawKeys = doWithKeys(connection -> connection.keys(rawKey)); + + return keySerializer != null ? SerializationUtils.deserialize(rawKeys, keySerializer) : (Set) rawKeys; } @Override - public Long countExistingKeys(Collection keys) { + public Cursor scan(ScanOptions options) { + Assert.notNull(options, "ScanOptions must not be null!"); - Assert.notNull(keys, "Keys must not be null!"); + return executeWithStickyConnection( + (RedisCallback>) connection -> new ConvertingCursor<>(connection.scan(options), + this::deserializeKey)); + } - byte[][] rawKeys = rawKeys(keys); - return doWithKeys(connection -> connection.exists(rawKeys)); + @Override + public K randomKey() { + + byte[] rawKey = doWithKeys(RedisKeyCommands::randomKey); + return deserializeKey(rawKey); + } + + @Override + public void rename(K oldKey, K newKey) { + + byte[] rawOldKey = rawKey(oldKey); + byte[] rawNewKey = rawKey(newKey); + + doWithKeys(connection -> { + connection.rename(rawOldKey, rawNewKey); + return null; + }); + } + + @Override + public Boolean renameIfAbsent(K oldKey, K newKey) { + + byte[] rawOldKey = rawKey(oldKey); + byte[] rawNewKey = rawKey(newKey); + return doWithKeys(connection -> connection.renameNX(rawOldKey, rawNewKey)); } @Override @@ -652,9 +705,12 @@ public Boolean expireAt(K key, final Date date) { }); } - // ------------------------------------------------------------------------- - // Methods dealing with value operations - // ------------------------------------------------------------------------- + @Override + public Boolean persist(K key) { + + byte[] rawKey = rawKey(key); + return doWithKeys(connection -> connection.persist(rawKey)); + } @Override public Long getExpire(K key) { @@ -664,7 +720,7 @@ public Long getExpire(K key) { } @Override - public Long getExpire(K key, final TimeUnit timeUnit) { + public Long getExpire(K key, TimeUnit timeUnit) { byte[] rawKey = rawKey(key); return doWithKeys(connection -> { @@ -677,32 +733,6 @@ public Long getExpire(K key, final TimeUnit timeUnit) { }); } - @Override - @SuppressWarnings("unchecked") - public Set keys(K pattern) { - - byte[] rawKey = rawKey(pattern); - Set rawKeys = doWithKeys(connection -> connection.keys(rawKey)); - - return keySerializer != null ? SerializationUtils.deserialize(rawKeys, keySerializer) : (Set) rawKeys; - } - - @Override - public Cursor scan(ScanOptions options) { - Assert.notNull(options, "ScanOptions must not be null!"); - - return executeWithStickyConnection( - (RedisCallback>) connection -> new ConvertingCursor<>(connection.scan(options), - this::deserializeKey)); - } - - @Override - public Boolean persist(K key) { - - byte[] rawKey = rawKey(key); - return doWithKeys(connection -> connection.persist(rawKey)); - } - @Override public Boolean move(K key, final int dbIndex) { @@ -710,40 +740,6 @@ public Boolean move(K key, final int dbIndex) { return doWithKeys(connection -> connection.move(rawKey, dbIndex)); } - @Override - public K randomKey() { - - byte[] rawKey = doWithKeys(RedisKeyCommands::randomKey); - return deserializeKey(rawKey); - } - - @Override - public void rename(K oldKey, K newKey) { - - byte[] rawOldKey = rawKey(oldKey); - byte[] rawNewKey = rawKey(newKey); - - doWithKeys(connection -> { - connection.rename(rawOldKey, rawNewKey); - return null; - }); - } - - @Override - public Boolean renameIfAbsent(K oldKey, K newKey) { - - byte[] rawOldKey = rawKey(oldKey); - byte[] rawNewKey = rawKey(newKey); - return doWithKeys(connection -> connection.renameNX(rawOldKey, rawNewKey)); - } - - @Override - public DataType type(K key) { - - byte[] rawKey = rawKey(key); - return doWithKeys(connection -> connection.type(rawKey)); - } - /** * Executes the Redis dump command and returns the results. Redis uses a non-standard serialization mechanism and * includes checksum information, thus the raw bytes are returned as opposed to deserializing with valueSerializer. diff --git a/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java b/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java index 62a9efa775..99991b83f4 100644 --- a/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java +++ b/src/main/java/org/springframework/data/redis/stream/StreamMessageListenerContainer.java @@ -445,8 +445,7 @@ public ConsumerStreamReadRequestBuilder consumer(Consumer consumer) { } /** - * Configure auto-acknowledgement for stream message consumption. This method is an alias for - * {@link #autoAck(boolean)} for improved readability. + * Configure auto-acknowledgement for stream message consumption. * * @param autoAck {@literal true} (default) to auto-acknowledge received messages or {@literal false} for external * acknowledgement.